先看一個實(shí)例
let a = [1,2,3];
let b = a;
console.log(b); //[1,2,3]
b[0] = 0;
console.log(a); //[0,1,2]
那么問題來了,在修改了b數(shù)組的元素之后,為什么a數(shù)組的元素也發(fā)生了變化了呢?
在說明這個問題之前我們需要了解JavaScript的數(shù)據(jù)類型。
基本數(shù)據(jù)類型&引用數(shù)據(jù)類型
在學(xué)習(xí)編程語言時,無論哪種語言都需要先了解該語言環(huán)境的數(shù)據(jù)類型,大多數(shù)編程語言中的數(shù)據(jù)類型都大同小異,在JavaScript中的數(shù)據(jù)類型大致分為“基本數(shù)據(jù)類型”和“引用數(shù)據(jù)類型”兩種。
基本數(shù)據(jù)類型
基本數(shù)據(jù)類型分為Number、String 、Boolean、Null和Undefined,基本數(shù)據(jù)類型指的是簡單的數(shù)據(jù)段;
let a = 'hello';
let b = a;
b = 'javascript';
在以上的代碼中,我們定義了變量a并且賦值了一個字符串‘string’給他,接著定義一個變量b并且將a賦值給b;那么按照我們正常的理解來說,a和b是等價(jià)的,至少值都是‘string’,但是實(shí)際在代碼的運(yùn)行環(huán)境里呢,他們是毫不相關(guān)的兩個東西。我們來了解一下以上代碼在內(nèi)存中的表現(xiàn)。

在創(chuàng)建了一個a的副本b后,由于基本數(shù)據(jù)類型的原因,a、b兩個變量在內(nèi)存中是兩個相互獨(dú)立的,任意一個的變化都是自己本身的變化,不對其他變量造成影響。
引用數(shù)據(jù)類型
即對象型類型,如:Object、Array、Function等,指的是有多個值構(gòu)成的對象。和基本數(shù)據(jù)類型不同的是,引用數(shù)據(jù)類型不能直接操作內(nèi)存中的值,而是通過操作數(shù)據(jù)的引用地址(指針)。
let obj = {name:'xx',age:20};
let obj1 = obj;
obj1.name = 'yy';
console.log(obj); //{name:'yy',age:20}
改變了obj1對象name屬性的值,原始對象obj的name屬性值也發(fā)生了相同的變化,引起這樣的“bug”在于obj和obj1都指向了一個相同的內(nèi)存地址相同的一個對象,自然在對一個對象引用的屬性值操作時,對象本身也會變化。
解決方案
如果有一個需求需要保留原始對象,而操作拷貝出的對象,那么簡單的新建變量賦值就不能解決這樣的問題??赡茉陂_發(fā)過程中或者是面試時,都會聽到淺拷貝、深拷貝這樣的概念,那么在這篇文章后,相信對于這兩個概念應(yīng)該會是印象深刻。對于深拷貝這樣的操作就是為了避免對原始數(shù)據(jù)的誤操作。
/**
* 引用數(shù)據(jù)類型的深拷貝
* @param {*} p : 需要拷貝的原始數(shù)據(jù)
* @param {*} c : 拷貝后輸出的數(shù)據(jù)
*/
function deepCopy(p, c) {
var c = c || {};
for (var i in p) {
if (typeof p[i] === "object") {
c[i] = (p[i].constructor === Array) ? [] : {};
deepCopy(p[i], c[i])
} else {
c[i] = p[i]
}
}
return c;
}