关于函数中this指向和闭包作用域的一道练习题
var x = 3,
obj = {x: 5};
obj.fn = (function(){
this.x *= ++x;
return function(y){
this.x *= (++x)+y;
console.log(x);
}
})();
var fn = obj.fn;
obj.fn(6);
fn(4);
console.log(obj.x, x);
- 首先还是浏览器开辟一块栈内存(ECStack)用于代码执行
- 形成全局上下文(EC(G)),声明并定义全局变量x,初始值为3;声明并定义全局变量obj,初始值为对象{x: 5}(需开辟堆内存保存对象0x001)
- 创建自执行函数(0x002)并将函数的执行结果赋值给,obj对象的属性fn
- 自执行函数执行,此时this指向为全局对象window,执行到this.x *= ++x这句代码时,操作的x都是全局中的x,即:window.x = window.x * (++window.x) = 12(全局变量x的值变为12)
- 在自执行函数中创建新的匿名函数(需开辟堆内存 0x003),并将函数的地址赋值给obj的fn属性;相当于obj.fn = function(y){this.x *= (++x)+y;console.log(x)}
- 全局上下文中的代码继续执行,将obj对象的属性fn所指向的堆地址赋值给全局变量fn,此时fn也是一个函数。
- 执行函数obj.fn(6) (0x003),形成私有上下文,因为是obj点fn,所以此时this指向的是obj对象,执行代码“this.x *= (++x)+y;console.log(x)”时,this指向的是obj,而++x中的x在当前私有上下文中不存在,于是向上级上下文中查找,发现在上级上下文中也不存在,继续向上查找,找到全局中的变量x(值为12),y则是当前私有上下文中的私有变量值为参数6。于是得到:obj.x = obj.x * ((++window.x) +y) = 5 * ((++12) +6) = 95。最终==obj.x = 95==
函数fn执行((0x003)),形成私有上下文,仍然执行代码:“this.x *= (++x)+y;console.log(x)”,此时this指向的是window,而++x中的x在当前私有上下文中不存在,于是向上级上下文中查找,发现在上级上下文中也不存在,继续向上查找,找到全局中的变量x(上一步自加后变为13),y则是当前私有上下文中的私有变量值为参数4,于是得:window.x = window.x * ((++window.x) + 4) = 13 *( 14 + 4) = 234,即 ==window.x = 234==
最后执行console.log(obj.x, x);依次输出95 234
- 一图解真相
