在阮一峰老师的微博上看到这样一道题:
javascript
function a(x, y) { y = function(){ x = 2; }; return function() { var x = 3; y(); console.log(x); }.apply(this, arguments); } a();
问:输出是多少?为什么?
我想到了答案,并且验证正确,小兴奋,在这里写下解题思路:
- 这道题的迷惑很多
-
return
其实没用,代码可以变成
javascript
function a(x, y) { y = function(){ x = 2; }; (function() { var x = 3; y(); console.log(x); }).apply(this, arguments); } a();
- 执行
a();
其实是执行
javascript
function() { 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
,这是为什么呢? 目前我还没搞明白,求解。
javascript
function 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
中定义的变量
之前我说y();
没用,为什么没用?是因为函数y
是定义在函数a
下的,所以y
的作用域链是这样的:
window
a
y
因为函数a
是这样定义的:function a(x, y)
,所以函数a
定义了变量x
,所以y
中的x = 2;
赋值给了函数a
的x
参数。并没有赋值给window
作用域下的x
,而console.log(this.x);
中this
指的是window,所以输出为undefined。
如果将函数a
的参数去掉,题目变成:
javascript
function 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 的匿名函数
里面,题目变为:
javascript
function 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语言的作用域很有帮助。虽然这道题对编程本身没有什么意义。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。