複製和引用複製

喆喆發表於2019-02-16

在程式語言中,賦值和引數傳遞可以通過value-copy(值複製)或者reference-copy(引用複製)來完成,這取決於使用的是什麼語法。

C語言中有指標這個概念,如果要向函式傳遞一個數並在函式中更改它的值,可以通過‘&’傳遞變數,這就是reference-copy;若是沒有宣告為引用的話,就是通過value-copy的方式傳遞。

但在JavaScript中沒有指標這個概念,但也有這兩種複製,不過,在語法上沒有區別,並且引用指向的是值。這兩種複製完全根據值的型別來決定。


// 第一種
let a = 2;
let b = a; // b是a的值一個副本,也就是value-copy
b++;
a; //2
b; //3
// 第二種
let c = [1, 2, 3];
let d = c;  // d是[1, 2, 3]的一個引用,引用指向的是值哦,這是reference-copy
d.push(4);
c; // [1, 2, 3, 4]
d; // [1, 2, 3, 4]

由上可知,基本型別的值是通過值複製的方式來賦值或是傳遞的,基本型別有null、undefined、字串、數字、布林以及ES6中的symbol。
引用型別的值是通過引用複製的方式來賦值或是傳遞的,引用型別有陣列、物件、函式等。
由於引用指向的是值本身而非變數,所以一個引用無法更改另一個引用的指向。也就是說,多個引用相互之間沒有引用/指向關係。關於這點,看程式碼就清楚了,如下:

let c = [1, 2, 3];
let d = c;  // 這時d和c都為[1, 2, 3]

d = [4, 5, 6];
c; // [1, 2, 3]
d; // [4, 5, 6]
// d = [4, 5, 6];這句賦值語句並不會影響c指向值[1, 2, 3],除非b是指向c的,但上面我們已經說過‘引用指向的是值本身而非變數’!!!
// 要知道直接賦值和push()是不一樣的,前者是重新引用,而後者是在引用的基礎上往裡面加東西。
// 若是想要在引用的基礎上清空陣列,可以用arr.length = 0的方式

特別要注意的一點是,那些基本型別,在初始化時,可以封裝成物件,可就算如此操作,還是更改不了‘它是基本型別值’的事實,所以還是value-copy,程式碼如下:

function add(x) {
    x += 1;
}
let a = new Number(1); // typeof a => object
add(a); 
a;  // a為2,而不是3  

相關文章