在阮一峰老师的微博上看到这样一道题:javascript
javascriptfunction a(x, y) { y = function(){ x = 2; }; return function() { var x = 3; y(); console.log(x); }.apply(this, arguments); } a();
问:输出是多少?为何?java
我想到了答案,而且验证正确,小兴奋,在这里写下解题思路:node
return
其实没用,代码能够变成javascriptfunction a(x, y) { y = function(){ x = 2; }; (function() { var x = 3; y(); console.log(x); }).apply(this, arguments); } a();
a();
实际上是执行javascriptfunction() { var x = 3; y(); console.log(x); }apply(this, arguments);
其中:1. this
是跟做用域(浏览器环境下是window,node环境下是global),由于是在跟做用域下执行的a();
。 2. arguments是空,由于a();
没有参数。编程
y();
没用。由于y定由于函数首先定义了var x = 3;
,因此console.log(x)
就是3。由于做用域优先级是从内向外由高到低的,因此在这里var x = 3;
的优先级是最高的,y();
中无论定义的什么,都不会影响到x
。因此以前分析了那么多,其实都没用啊!作题时读代码,顺序要从内部到外部(仅限于作题)~问题:这道题若是将输出改为console.log(this.x)
,答案会是什么? 我认为是2
,但是结果确实undefined
,这是为何呢? 目前我还没搞明白,求解。浏览器
javascriptfunction a(x, y) { y = function(){ x = 2; }; return function() { var x = 3; y(); console.log(this.x); }.apply(this, arguments); } a();
我弄明白了上面的问题,重点在于:1. 函数y
的做用域,2. 函数a
中定义的变量app
以前我说y();
没用,为何没用?是由于函数y
是定义在函数a
下的,因此y
的做用域链是这样的:函数
windowthis
acode
yip
由于函数a
是这样定义的:function a(x, y)
,因此函数a
定义了变量x
,因此y
中的x = 2;
赋值给了函数a
的x
参数。并无赋值给window
做用域下的x
,而console.log(this.x);
中this
指的是window,因此输出为undefined。
若是将函数a
的参数去掉,题目变成:
javascriptfunction a() { y = function(){ x = 2; }; return function() { var x = 3; y(); console.log(this.x); }.apply(this, arguments); } a();
这样函数a
中就没有x
这个变量了,因此函数y
中的x = 2;
就会赋值给跟做用域下的x
,因此console.log(this.x);
的输出就会变成2
。
再将题目改一下,若是将函数y()
定义在return 的匿名函数
里面,题目变为:
javascriptfunction a(x, y) { return function() { y = function(){ x = 2; }; var x = 3; y(); console.log(x); }.apply(this, arguments); } a();
问console.log(x)
会输出什么? 答案是2
,由于此时y
的做用域链是这样的:
window
a
匿名函数
y
由于匿名函数中定义了var x = 3;
,因此函数y
中的x = 2;
就会修改匿名函数中的x
的值,因此console.log(x)
输出变成了3,
弄明白这道题的每一处细节,对理解javascript语言的做用域颇有帮助。虽然这道题对编程自己没有什么意义。