我们先看下面一个例子:
var a = 10;
function test(){
a = 100;
console.log(a);
console.log(this.a);
var a;
console.log(a);
}
test();
输出结果为:100, 10, 100
分析:
- 首先函数执行前进行扫描,得到函数中存在一个局部变量a,将a添加到函数的活动变量对象中,从而在作用域链中能够找到该局部变量a。此时a的值为undefined。
- 执行赋值语句
a = 100;
后,更新活动对象中a的值为100 - 执行
console.log(a);
读取当前执行环境中的作用域链,首先读取作用域链前端即test()函数的活动对象,读取到局部变量a的定义,即100。因此第一个输出为100。 - 执行
console.log(this.a);
语句,由于在全局环境中调用test()函数,因此这儿的this指向window,等价于执行console.log(window.a);
。因此第二个输出为10。 - 执行
var a;
语句。JS中再次定义一个同名变量(不初始化),会忽略第二次的定义。因此此语句无效。 - 最后执行
console.log(this.a);
语句,依旧是访问全局变量a,因此输出100。
再看下面一个例子:
var a = 100;
function test(){
console.log(a);
var a = 10;
console.log(a);
}
test();
输出结果为:undefined, 10
分析:
- 首先函数执行前进行扫描,得到函数中存在一个局部变量a,将a添加到函数的活动变量对象中,从而在作用域链中能够找到该局部变量a。此时a的值为undefined。
- 执行
console.log(a);
,读取当前执行环境中的作用域链,首先读取作用域链前端即test()函数的活动对象,读取到局部变量a的定义,值为undefined,因此第一个输出为undefined。 - 执行
var a = 10;
,先读取作用域链前端即test()函数的活动对象,读取到局部变量a的定义,更新值为10。 - 执行
console.log(a);
,读取当前执行环境中的作用域链,首先读取作用域链前端即test()函数的活动对象,读取到局部变量a的定义,值为10,因此第二个输出为10。