在阮一峯老師的微博上看到這樣一道題: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語言的做用域頗有幫助。雖然這道題對編程自己沒有什麼意義。