對於“JavaScript 函數參數是傳值(byVal)還是傳址(byRef)”這個問題,普遍存在一個誤區:number,string等“簡單類型”是傳值,Number, String, Object, Array等“複雜類型”是傳址。
這樣不對嗎?為什麼會有這樣的誤區?看一下這兩段代碼:
複製代碼 代碼如下://造成傳值假象的代碼
function modifyLikeByVal(x){
x = 1;
console.log('x = %d', x);
}
var x = 0;
console.log('x = %d', x); // 輸出 x = 0
modifyLikeByVal(x); // 輸出 x = 1
console.log('x = %d', x); // 輸出 x = 0 x沒變!
複製代碼 代碼如下://造成傳址假象的代碼
function modifyLikeByRef(x){
x[0] = 4;
x[1] = 5;
x[2] = 6;
console.log('x = [ %s ]', x.join(', '));
}
var x = [1, 2, 3];
console.log('x = [ %s ]', x.join(', ')); // 輸出 x = [ 1, 2, 3 ]
modifyLikeByRef(x); // 輸出 x = [ 4, 5, 6 ]
console.log('x = [ %s ]', x.join(', ')); // 輸出 x = [ 4, 5, 6 ] x變了!
於是,由以上代碼得出結論,“簡單類型”作為參數是傳值(byVal)的,“複雜類型”作為參數是傳址(byRef)的。
問題出在哪呢?
仔細觀察兩個函數,就可以發現一點:
在byVal中,是直接修改了參數x: x = 1;
而byRef中,是修改參數x的成員: x[0] = 4; x[1] = 5; x[2] = 6;
本人由此得出猜想:在JavaScript中,所有的變數或成員,都是一個指標,在修改變數或成員值的時候,其實是修改了該指標的地址。
這樣上面的代碼就可以得到解釋了:
在“byVal”中:
複製代碼 代碼如下:global { // 表示全域範圍,下面的表示函數範圍
var x = 0; // 初始化指標x並指向數字0
fun(x) {
x = global.x; // 傳入參數global.x; fun域的x指標地址與global域的x指標地址一樣指向數字0
x = 1; // 修改fun域的x指標地址,指向數字1;
} // fun 域結束,global域中的x指標沒改變
}
在“byRef”中:複製代碼 代碼如下:global { // 表示全域範圍,下面的表示函數範圍
/*
初始化指標x並指向數組[1, 2, 3]
其實是x的三個成員0, 1, 2,分別指向1, 2, 3;
*/
var x = [1, 2, 3];
fun(x) {
x = global.x; // 傳入參數global.x; fun域的x指標地址與global域的x指標地址一樣指向數組[1, 2, 3]
/*
在fun域中的x沒有再被改變
緊接著修改fun域中的x(也就是global.x)三個成員指標的指向
*/
x[0] = 4;
x[1] = 5;
x[2] = 6;
} // fun 域結束,global域中的x指標沒改變,但其三個成員指標被改變了,於是就看到我們輸出的結果
}
那這段代碼怎麼解釋呢???複製代碼 代碼如下:(function(a, b){
arguments[0] = 1;
b = 2;
console.log(arguments, a, b);
})(-1, -2);
只能說a, b...,是arguments[0],...[n]的別名了。
如果有不對的地方,請指出來,謝謝。
如果有更好的解釋,歡迎大家分享。