javascript - 函數設定參數預設值的問題
巴扎黑
巴扎黑 2017-07-05 10:37:59
0
7
832
var x = 1; 

function foo(x,y=function(){x=2;}){
    var x = 3;
    y();
    console.log(x); 
}
foo();

這段程式碼出現在阮一峰老師寫的es6那本書,最後輸出3,文字說明說y中的x和var x = 3;的x不是同一個x,這兒有點不理解。
然後把var x= 3 的var去掉,就能輸出2,更不懂了。 。 。希望能有解答

巴扎黑
巴扎黑

全部回覆(7)
女神的闺蜜爱上我

這裡其實是涉及到 ES6 預設參數所引入的一個中間作用域。這個問題當初阮一峰也弄錯過,當然這裡是正確的。

中間作用域的目的是防止預設參數被函數裡面的變數污染。預設參數本意是為了讓參數有預設值,假如函數內部的變數還能提升上來,那麼預設參數就沒意義了。具體的解釋和例子可以看文章。

所以看回問題,

var x = 1; 

function foo (x2, y = function () { x = 2; }) {
    var x = 3;
    y();
    console.log(x); 
}
foo();

這裡有三個作用域,把 x 由外到裡標記出來就是:

var x1 = 1; 

function foo (x2, y = function () { x2 = 2; console.log(x2); }) {
    var x3 = 3;
    y();
    console.log(x3); 
}
foo();
console.log(x1);

假如沒有了參數的 x,那麼標記出來就是:

var x1 = 1; 

function foo (y = function () { x1 = 2; console.log(x1); }) {
    var x2 = 3;
    y();
    console.log(x2); 
}
foo();
console.log(x1);
阿神

y()修改的是foo函數的參數x,並非全域x。 (這裡你可以在y()呼叫後,console.log(x),可發現全域x還是1.)
問題就簡單了: 1) 當用var x = 3時,foo裡面的console.log(x )印出來的就是foo裡的局部變數x,y()修改的只是參數x,所以最終輸出是局部變數x = 3
2)當不用var時,foo裡的所有x都指向參數x,而用y ()把參數x修改為2,最終輸出2

Ty80

y 的預設值改變的是全域變數的x;
把var x= 3 的var去掉,就能輸出2 是因為在foo的作用域內找不到x,所以在往上尋找,找到全域變數x,此時已被賦值為2

Peter_Zhu

這是局部變數和全域變數生命週期的區別,方法裡面的var x = 3;是局部變量,兩個變數同名,方法體裡面會使用局部變量,不會使用全域變量,所以輸出的是var x = 3;這個x的值;當你去掉var x = 3;的var,表示在方法裡面沒有另外定義局部變量,使用的是全域變數x,而你方法參數又把這個全域變數值修改為2,所以輸出為2;

扔个三星炸死你

首先你要理解var操作符的定義,用var操作符定義的變數將成為定義該變數的作用域中的局部變量,也就是說,如果在函數中使用var定義一個變量,那麼這個變數屬於函數的局部變量,在函數退出時即被銷毀,而不使用var直接定義的變數都會成為全域變數。
另一個你要理解的概念是作用域鏈的問題,程序查找一個變數時,首先會在當前作用域內查找,若沒有找到則順著作用域鏈依次向上查找,遍歷完都沒有則報undefined。
回到上面的程式碼,首先在全域作用域中利用var定義x=1; x 即屬於全域變量,接下來在函數foo內部定義了局部變數var x=3;X就屬於函數的局部變量,接著執行y函數,對全域變數x進行修改賦值,這時x變成2,記住此時修改的是全域變數x而不是局部變數X,接下來列印x時,函數會依據作用域鏈先在函數內部查找x的值,找到x=3後即輸出值,所以結果為3,若把var x=3的var去掉,則x變為全域變量,修改x就如同y函數中x賦值一樣,這時只存在一個全域變數x,依照程式碼執行順序,內部先修改全域變數X為3,然後y函數修改全域變數x為2,列印時,順著作用域鏈,在函數內部沒有找到x值,接著在全域作用域中查找,此時X為2,所以結果為2

熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板