当JavaScript代码执行一段可执行代码(executable code)时,会建立对应的执行上下文(execution context)。javascript
对于每一个执行上下文,都有三个重要属性:html
前面已经讲解了this,今天来说讲做用域及做用域链。前端
做用域是指程序源代码中定义变量的区域。java
做用域规定了如何查找变量,也就是肯定当前执行代码对变量的访问权限。git
JavaScript 采用词法做用域(lexical scoping),也就是静态做用域。github
所谓的词法做用域,就是代码在编写过程就体现出来的做用范围。代码一旦写好,不用执行, 做用范围就已经肯定好了,这个就是所谓的词法做用域。函数
词法做用域的规则:post
*与词法做用域相对的是动态做用域,函数的做用域是在函数调用的时候才决定的。ui
var value = 1;
function foo() {
console.log(value);
}
function bar() {
var value = 2;
foo();
}
bar(); // 1
复制代码
分析下执行过程:this
执行 foo 函数,先从 foo 函数内部查找是否有局部变量 value,若是没有,就根据书写的位置,查找上面一层的代码,也就是 value 等于 1,因此结果会打印 1。
假设JavaScript采用动态做用域,让咱们分析下执行过程:
执行 foo 函数,依然是从 foo 函数内部查找是否有局部变量 value。若是没有,就从调用函数的做用域,也就是 bar 函数内部查找 value 变量,因此结果会打印 2。
看一个《JavaScript权威指南》中的例子:
var scope = "global scope";
function checkscope(){
var scope = "local scope";
function f(){
return scope;
}
return f();
}
checkscope();
复制代码
var scope = "global scope";
function checkscope(){
var scope = "local scope";
function f(){
return scope;
}
return f;
}
checkscope()();
复制代码
两段代码都会打印:local scope
。由于JavaScript采用的是词法做用域,函数的做用域基于函数建立的位置。
引用《JavaScript权威指南》的回答就是:
JavaScript 函数的执行用到了做用域链,这个做用域链是在函数定义的时候建立的。嵌套的函数 f() 定义在这个做用域链里,其中的变量 scope 必定是局部变量,无论什么时候何地执行函数 f(),这种绑定在执行 f() 时依然有效。
当查找变量的时候,会先从当前上下文的变量对象中查找,若是没有找到,就会从父级(词法层面上的父级)执行上下文的变量对象中查找,一直找到全局上下文的变量对象,也就是全局对象。这样由多个执行上下文的变量对象构成的链表就叫作做用域链。
这里不具体介绍函数的[[scope]]属性,只介绍一下怎么简单的分析做用域链。
做用域链绘制规则以下:
以代码为例:
function func1(){
alert(num);
}
function func2(){
var num=456;
function func3(){
func1();
}
func3();
}
func2();//结果显示:num is not defined
复制代码
上述代码做用域链以下:
分析下代码执行流程:
请注意:
相关系列: 从零开始的前端筑基之旅(超级精细,持续更新~)
若是你收获了新知识,就给做者点个赞吧~他急需支持~
参考文章:
- ****JavaScript深刻之词法做用域和动态做用域****
- ****JavaScript深刻之做用域链****
- ****JS-词法做用域 做用域链****