對於「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中,所有的變數或成員,都是一個指針,在修改變數或成員值的時候,其實是修改了該指標的位址。
複製程式碼
程式碼如下:
程式碼如下:
global {> / 表示全域作用域,下列的表示函數作用域
var x = 0; // 初始化指標x並指向數字0
fun(x) {
在“byRef”中:
複製代碼
程式碼如下:
global { // 表示全域作用域,下面的表示函數作用域
/*
初始化指標並指向陣列[1,指向陣列[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)三個成員指針的指向 🎜> = 4;
複製程式碼
程式碼如下:
(function(a, b){
[0] = 1;
b = 2;
console.log(arguments, a, b);
})(-1, -2);})(-1, -2);隻隻有能說a, b...,是arguments[0],...[n]的別名了。
如果有不對的地方,請指出來,謝謝。
如果有更好的解釋,歡迎大家分享。