作用域链
当一个块或函数嵌套在另一个块或函数中时,就发生了作用域的嵌套。因此,在当前作用域中无法搜索到某个变量时,引擎就会在外层嵌套的作用域中继续搜索,直到搜索到该变量,或抵达最外层的作用域(也就是全局作用域)为止。这样一条有序的列表,称为作用域链,作用域链的最前端一定是当前作用域,最末端是全局作用域。
var b = 0;
console.log("全局作用域下,b="+b);//"全局作用域下,b=0"
function test(){
console.log(b); // b=0
function innerTest(){
var b = 2;
console.log("当前作用域下,b="+b);//"当前作用域下,b=2"
}
return innerTest();
}
test();
- 如上代码所示,第一次打印变量 b 是在全局作用域下,b = 0;
- 第二次打印时,变量 b处于函数 test()作用域内,由于在test() 作用域内未对变量 b 进行定义,所以返回上一层调用全局作用域内定义的变量 b;
- 第三次打印时,变量 b 处于 test 下的 innerTest() 内,由于在 innerTest() 内重新定义了 b (局部变量),所以 b = 2。
简单点来说,作用域链就是一条变量对象的链。
{
Scope:
[
{ //当前作用域
变量,
函数名
},
{ //上一层作用域
变量,
函数名
}
...
{ //全局作用域
变量,
函数名
}
]
}
为了加深理解,我们来看几道题目
var a = 1
function fn1(){
function fn2(){
console.log(a)
}
function fn3(){
var a = 4
fn2()
}
var a = 2
return fn3
}
var fn = fn1()
fn() //输出多少?
解析: 2,fn1() 返回的是 fn3 函数,被赋值给了 fn 。那么当执行 fn() 时 ,也就是执行 fn3()。在 fn3() 内 执行了 fn2() 函数,在 fn2() 中又打印了 a,但此时在 fn2() 未对变量 a 进行定义,所以需要返回到创建 fn2() 函数的作用域内寻找定义好的 a 变量,可以发现在 fn1() 内 var a = 2
,所以输出 a = 2。(如若此层作用域未定义变量 a ,那就接着往上一层作用域寻找。)
var a = 1
function fn1(){
function fn3(){
function fn2(){
console.log(a)
}
var a
fn2()
a = 4
}
var a = 2
return fn3
}
var fn = fn1()
fn() //输出多少
解析: undefined,fn1() 返回的是 fn3 函数,被赋值给了fn。执行 fn() 也就是执行 fn3()。当执行fn3() 时,我们可以发现在 fn3() 循环体内,只是先声明了 a ,只有执行 fn2() 之后才对 a 进行赋值。那么在执行 fn2() 输出 a 时,只能输出 undefined 。