执行上下文和做用域,做用域链

  • 给执行上下文环境下一个通俗的定义——在执行代码以前,把将要用到的全部的变量都事先拿出来,有的直接赋值了,有的先用undefined占个空。(变量的值是在执行过程当中产生的肯定的)
  •  javascript除了全局做用域以外,只有函数对象不建立做用域能够建立的做用域。(ES6新加了块级做用域 let)

 

全局代码的上下文环境数据内容为:javascript

 

普通变量(包括函数表达式),java

如: var a = 10;函数

声明(默认赋值为undefinedthis

函数声明,spa

如: function fn() { }code

赋值对象

thisblog

赋值ip

 

若是代码段是函数体,那么在此基础上须要附加:作用域

 

参数

赋值

arguments

赋值

自由变量的取值做用域

赋值

做用域在函数定义时就已经肯定了,而不是在函数调用时肯定。做用域有上下级的关系,上下级关系的肯定就看函数是在哪一个做用域下建立的。例如,fn做用域下建立了bar函数,那么“fn做用域”就是“bar做用域”的上级。做用域最大的用处就是隔离变量,不一样做用域下同名变量不会有冲突。

 

 

 

做用域只是一个“地盘”,一个抽象的概念,其中没有变量。要经过做用域对应的执行上下文环境来获取变量的值。

 

一个例子:

for (var i = 0; i < 5; i++) {
    setTimeout(function() {
        console.log( i);
    }, 1000);
}

console.log(i);

若是咱们约定,用箭头表示其先后的两次输出之间有 1 秒的时间间隔,而逗号表示其先后的两次输出之间的时间间隔能够忽略,代码实际运行的结果该如何描述?

结果是5->5,5,5,5,5。由于i是个自由变量,当循环结束时,i已经等于5了,而setTimeout中的函数还未执行,等其执行时,获取的i为5。

若想输出5->0,1,2,3,4,利用 JS 中基本类型(Primitive Type)的参数传递是按值传递(Pass by Value)的特征便可。

方法一:IIFE

for (var i = 0; i < 5; i++) {
    (function(j) {  // j = i
        setTimeout(function() {
            console.log(j);
        }, 1000);
    })(i);
}

console.log( i);

方法二:

 

var output = function (i) {
    setTimeout(function() {
        console.log(i);
    }, 1000);
};

for (var i = 0; i < 5; i++) {
    output(i);  // 这里传过去的 i 值被复制了
}

console.log(i);

 

自由变量:

在A做用域中使用的变量x,却没有在A做用域中声明(即在其余做用域中声明的),对于A做用域来讲,x就是一个自由变量。以下图 

如上程序中,在调用fn()函数时,函数体中第6行。取b的值就直接能够在fn做用域中取,由于b就是在这里定义的。而取x的值时,就须要到另外一个做用域中取。到哪一个做用域中取呢?

要到建立这个函数的那个做用域中取值——是“建立”,而不是“调用”,—其实这就是所谓的“静态做用域”。

做用域链:

 

上面描述的只是跨一步做用域去寻找。

 

若是跨了一步,还没找到呢?——接着跨!——一直跨到全局做用域为止。要是在全局做用域中都没有找到,那就是真的没有了。

 

这个一步一步“跨”的路线,咱们称之为——做用域链。

咱们拿文字总结一下取自由变量时的这个“做用域链”过程:(假设a是自由量)

第一步,如今当前做用域查找a,若是有则获取并结束。若是没有则继续;

第二步,若是当前做用域是全局做用域,则证实a未定义,结束;不然继续;

第三步,(不是全局做用域,那就是函数做用域)将建立该函数的做用域做为当前做用域;

第四步,跳转到第一步。

相关文章
相关标签/搜索