一、作用域(what?)

  官方解释是:“一段程序代码中所用到的名字并不总是有效/可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。”
  单从文字理解比较难懂,举个栗子:

function outer(){
// 声明变量
var name = "ukerxi"; // 定义内部函数
function inner() {
console.log(name); // 可以访问到 name 变量
}
}
console.log(name); // 报错,undefined

  其中变量name声明在 oute r函数中,当在 outer 中定义一个 inner 函数进行输出 name,可以得到正确的值,而在 outer 外进行输出 name 出现 undefined 错误;在此可以看出 outer 函数即为 name 变量的作用域(证明过程比较粗略,但结论还是正确的--_--);

二、作用域(why?)

  作用域的使用,提高了程序的逻辑的局部性,增强程序的可靠性,以及避免命名冲突;为代码的模块化开发提供便利;根据上面提到的函数作用域,name 变量被局限在了 outer 函数中,在其他的函数中也可以定义相同名字的变量,两者之间不会互相影响;

三、js 中的作用域

  先说ES5版本及更低版本的,因为在 ES6 上,重新定义了几个决定作用域的关键字;

  1. 没有块级作用域
    在javaScript中,不像C、java等拥有块级作用域;常见块级作用域,例如:

    // C语言实现
    for(int i= 0; i<10; i++){
    // 中括号里面就是块级作用域
    } if(ture){
    int i = 1;
    // 这里也是块级作用域
    }
    printf("%d/n",i); // --“use an undefined variable:i”
    //这里是访问不到for语句中的i与if语句中的i变量的

    当然这些在javaScript中是没有的,一般来说只有块级作用域;所以使用时须注意作用域的影响,例如:

    for(var i= 0; i<10; i++){
    // do something
    } console.log(i); // --10

    在程序设计过程中可以使用函数作用域,进行模拟块级作用域;例如:

    function loop(){
    for(var i= 0; i<10; i++){
    // do something
    }
    }
    loop();
    console.log(i); // --undefined

    javaScript是灵活可变的,同样上面这个例子,可以使用自执行函数重写实现,这样就减少了调用这一步;

    (function (){
    for(var i= 0; i<10; i++){
    // do something
    }
    }());
    console.log(i); // --undefined
  2. ES6中的作用域
    在ES6中新增加了(let,const)关键字,进行定义变量,解决了没有块级作用域的限制;
    let:let允许你声明一个作用域被限制在块级中的变量、语句或者表达式。与var关键字不同的是,它声明的变量只能是全局或者整个函数块的。let声明的变量只在其声明的块或子块中可用,这一点,与var相似。二者之间最主要的区别在于var声明的变量的作用域是整个封闭函数。
    具体如下:
    function range () {
    // let 和var 相同的地方,都有函数作用域
    var name = 'ukerxi';
    let nameOuter = 'outer'; for (var j = 0; j < 1; j++) {
    console.log(name)
    }
    console.log("输出j变量", j); // ==> 1
    for (let i = 0; i < 1; i++) {
    console.log(nameOuter)
    }
    console.log("输出i变量", i); // 报错 undefined
    }

    可以看出,使用let 定义的i变量,在for语句外进行输出时,会进行报错,说明i不在该作用域内,i的作用域在for包裹的作用内;

  3. 作用域链
    每个函数都有自己的执行环境,包含当前环境的变量访问关系,与之相关联的就是“变量对象”,如果是当前函数的变量对象,也可称为“活动对象”;此对象中包含了,当前函数可访问的变量及函数;变量对象,最开始包含的对象是参数的arguments对象,然后是在函数中定义的其他变量及方法;例如:
    function fn(name){
    var text = "test";
    }
    // 变量对象中包含:命名函数fn变量、参数name、内部变量test

    当然这个变量对象是不可访问的,只提供后台引擎编译执行使用;当定义有多个变量对象嵌套,这些变量对象就组成了作用域链;例如:

    var name = "global";
    function super() {
    var name = "super";
    function sub(){
    var name = "sub";
    }
    }

    作用域链:

    在作用域最前端的是活动对象,而最后端是全局执行环境window(浏览器宿主中);变量访问原则是,根据作用域前端往上进行搜索,如果提前搜索到变量,则停止搜索,例如上面这个例子中,name变量的值是"sub"因为其在最前端的变量对象中已经定义了,就不会往上继续检索;

  4. 延长作用域
    有两种方法可以将作用域进行延长:
    ①、try-catch 语句的catch块
    ②、with 语句

    两个语句都是在原本的作用域最前端进行添加一个变量对象;例如:

    var name = "global";
    function test(){
    var name = "sub";
    with(window){
    console.log(name);
    }
    } test(); // -- "global"

    作用域链:


    所以检索变量时,会先在最前端的window变量对象中检索;当然,在严格模式下已经禁用了with语句,编程时,最好向后兼容,废弃使用with语句;

  5. 执行环境只与函数的声明及定义位置有关
    当一个函数定义后其执行环境与作用域链就已经确定了,不会因为执行位置改变而改变,具体例子:
    var name = "global";
    function getName(){
    console.log(name);
    } function test (){
    var name = "inner";
    getName();
    } // 执行test
    test(); // -- global

    运行test 函数,其中test 函数执行的是 getName 进行输出 name 变量,输出的是全局变量的信息;即当 getName 定义时就已经确定了自己的作用域及执行环境,因而不会因为执行位置的不同而输出不同的信息;当然有一种情况不一样,那就是灵活的 this

  6. this的动态绑定
    与作用域链及执行环境不同,this是根据执行时的接受者进行绑定的,改变this的几种方法:
    ①、new 关键字
    ②、call / apply 方法
    ③、直接调用构造函数

    具体例子如下:

    // 声明一个类
    function Person (){
    this.name = "ukerxi";
    }
    // 使用new关键字,使this执行新建对象
    // 其实是构造函数默认返回this
    var men1 = new Person(); // this绑定到men1上 // 声明一个空对象,使用call/apply 进行绑定
    var men2 = {};
    Person.call(men2); // this绑定到men2上 // 直接执行构造函数
    Person(); // this绑定到window上(使用严格模式则会报错,this指向undefined)

【结束语】

系列文章,包括了原创,翻译,转载等各类型的文章;一方面是为了自己总结,另一方面页希望可以共享知识;在技术方面有输入,也要有所输出,才能更进一步!文章基于自己的实践、阅读及理解,如有不合理及错误的地方,烦请各大佬评论指出,以便改正,感谢!

js作用域与执行环境(前端基础系列)的更多相关文章

  1. JS 作用域(执行环境)与作用链---JS 学习笔记(二)

    一  作用域(执行环境) 作用域:定义了变量和函数有权访问的其他数据,决定了他们各自的行为.--------<JS高级程序设计>4.2 好难理解啊~参考了参考尤克希的博客内容,大体上理解了 ...

  2. js中的执行环境及作用域

    最近在面试时被问到了对作用域链的理解,感觉当时回答的不是很好,今天就来说说js中的作用域链吧. 首先来说说js中的执行环境,所谓执行环境(有时也称环境)它是JavaScript中最为重要的一个概念.执 ...

  3. js中的执行环境和作用域链

    首先介绍一些即将用到的概念: 执行环境:  它定义了变量和函数有权访问其他数据的范围,每一个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个变量对象中.   所有javasc ...

  4. JS中的执行环境和作用域

    window 是最大最外围的执行环境,然后每个函数都有自己的执行环境.JS代码是从上到下执行的,单纯的用语言描述可能会有点绕,而且不大直观.我们看着代码来 console.log('global be ...

  5. “use strict” 严格模式使用(前端基础系列)

    ECMAscript5添加一种严格模式的运行模式("use strict"),让你的js语句在更加严格的环境下进行运行: 一.主要作用: 消除版本javascript中一些不合理及 ...

  6. 深入理解js——作用域和上下文环境

    如图除全局作用域外,每个函数都会创建自己的作用域.作用域在函数定义时就确定了,而不是在函数调用时确定. 下面按照程序执行的步骤加上上下文环境. 第一步:程序加载时已经确定全局上下文环境,并随着程序的执 ...

  7. navigator.userAgent浏览器检测(前端基础系列)

    对于前端来说,浏览器检测已经不陌生了,在做一些页面是,需要针对不同的浏览器进行处理不同的逻辑,最简单的就是区分pc和移动端的浏览器,或是android 和ios下的浏览器. 一.浏览器检测的由来?  ...

  8. 前端基础系列——CSS规范(文章内容为转载)

    原作者信息 作者:词晖 链接:http://www.zhihu.com/question/19586885/answer/48933504 来源:知乎 著作权归原作者所有,转载请联系原作者获得授权. ...

  9. javascript 命名空间与运用(前端基础系列)

    所谓代码,当你随便命名一个变量:var name = "ukerxi"; 就是一句代码:但当你的代码写出来后,对于后续维护及阅读的人,就可以看出代码是否,易读,易理解:优雅的代码总 ...

随机推荐

  1. Numpy数组索引为-1和None

    numpy的数组操作方便,可以用:来切片,用布尔数组或者布尔表达式来查找符合条件的数据,也可以用数组作为另一个数组的索引来查找指定的数据.但有时也会见到数组索引为-1和None.两者的用法如下: 1. ...

  2. 分酒问题(DFS解法)

    题目大概是这样: 已知有三个容量分别为3千克.5千克和8千克的并且是没有刻度的酒瓶,3千克和5千克的瓶子均装满了酒,而8千克的瓶子为空.现要求仅用这三个酒瓶将这些酒均分为两个4千克并分别装入5千克和8 ...

  3. js 作用域,作用域链,闭包

    什么是作用域? 作用域是一种规则,在代码编译阶段就确定了,规定了变量与函数的可被访问的范围.全局变量拥有全局作用域,局部变量则拥有局部作用域. js是一种没有块级作用域的语言(包括if.for等语句的 ...

  4. zabbix 3.2 高可用实现方式一,亲测无坑

    1.架构设计图 2.设计说明 1. 基础架构为LAMP环境,采用keepalived实现zabbix服务器高可用,保证主server的mysql或者httpd宕掉后能切换到从server. 2.数据库 ...

  5. 如何运用GitHub来提高生产效率

    这是一篇GitHub的入门级文章,主要针对git的初学者.我们将讨论初学者最关心的一些问题,如:为什么我们要使用GitHub,它的应用有哪些,如何运用它去帮助我们提高工作效率,以及它的基本用法有哪些. ...

  6. linux mysql无故无法启动了,centos 7

    转自: http://support.moonpoint.com/software/database/mysql/not-running-centos7.php 下面简单翻译一下. 详细内容可以阅读英 ...

  7. 二:熟悉 TCP/IP 协议

    一篇文章带你熟悉 TCP/IP 协议(网络协议篇二) 同样的,本文篇幅也比较长,先来一张思维导图,带大家过一遍. 一图看完本文 一. 计算机网络体系结构分层 计算机网络体系结构分层计算机网络体系结构分 ...

  8. 用C#生成不重复的随机数

    我们在做能自动生成试卷的考试系统时,常常需要随机生成一组不重复的题目,在.net Framework中提供了一个专门用来产生随机数的类System.Random. 对于随机数,大家都知道,计算机不 可 ...

  9. 三:动态SQL

    :动态SQL 1.使用动态sql完成多条件查询 If:利用if实现简单的条件选择 Choose(when,otherwise):相当于java中的switch语句,通常与whenhe otherwis ...

  10. 使用dropwizard(3)-加入DI-dagger2

    前言 习惯了Spring全家桶,对spring的容器爱不释手.使用dropwizard,看起来确实很轻,然而,真正使用的时候不得不面临一个问题.我们不可能一个resource就能把所有的业务逻辑囊括! ...