阮一峯老師微博上的關於js做用域的一道題

在阮一峯老師的微博上看到這樣一道題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;賦值給了函數ax參數。並無賦值給window做用域下的xconsole.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語言的做用域頗有幫助。雖然這道題對編程自己沒有什麼意義。

相關文章
相關標籤/搜索