昨天翻了下陣列api,看到concat和slice方法,突然想到這個兩個方法是淺拷貝還是深拷貝,結果陷入了死胡同,為什麼mdn文件說是淺拷貝,但進行簡單的操作為什麼能複製成功啊,糾結半天後才弄清原由,原來我一直把賦值和深淺拷貝搞混了。
首先不要把引用型別的賦值歸結為淺拷貝,深拷貝和淺拷貝只針對像 object, array 這樣的複雜物件的。簡單來說,淺拷貝只拷貝一層物件的屬性,而深拷貝則遞迴拷貝了所有層級。
js資料型別
基本型別為number、string、boolean、undefined、null,引用型別為object。
基本型別是儲存存放在棧記憶體中的簡單資料段,資料大小確定,記憶體空間大小可以分配,是直接按值存放的,所以可以直接訪問。
引用型別存放在堆記憶體中,它的變數實際是存放在棧中的乙個位址(指標)指向堆中的實際記憶體位址。
區分賦值、淺拷貝與深拷貝
** 賦值**
基本型別賦值(=)直接在棧中開闢新記憶體,把值賦值到新記憶體中,而引用型別的賦值(=)是直接複製棧記憶體中的位址(指標),並沒有在堆記憶體總開闢新的記憶體,因此他們都指向同乙個堆記憶體,任何操作都會影響原來的資料。
let obj2 = obj1;
複製**
淺拷貝與深拷貝
首先不要把賦值和淺拷貝和深拷貝混在一起。
淺拷貝和深拷貝都在堆記憶體中開闢新的記憶體,都進行了複製。
淺拷貝就是進行簡單的複製,只會將物件的各個屬性進行依次複製,不會遞迴複製,所以那些子屬性如果再是引用型別(物件、陣列、函式)的話,就只複製了他們的位址(指標),實際的記憶體位址沒有被複製。
所以就理解為什麼陣列方法slice、concat、擴充套件運算子、object.assign()這些都是淺拷貝了。它們都進行了簡單的拷貝,沒有再對深層次的資料進行拷貝。
深拷貝是對物件以及物件的所有子物件進行拷貝。
常見的淺拷貝
擴充套件運算子(...);
object.assign();
array.prototype.concat();
array.prototype.slice();
lodash(_.clone());
複製**
深拷貝例子
json.parse(json.stringify());
雖然用起來很方便,但是,只適合一些簡單的情景(number, string, boolean, array, object),扁平物件,那些能夠被 json 直接表示的資料結構。function物件,regexp物件是無法通過這種方式深拷貝。
let obj2=json.parse(json.stringify(obj1));
複製**
遞迴賦值;
function deepclone(obj);
if(obj && typeof obj==="object")else{
//如果不是,簡單複製
objclone[key] = obj[key];
return objclone;
複製**
lodash(_.clonedeep());
let obj2 = _.clonedeep(obj1);
複製**
結尾:如果**有錯誤希望多多指教。
JS賦值 淺拷貝和深拷貝
賦值 當我們把乙個物件賦值給乙個新的變數時,賦的其實是該物件在棧中的位址,而不是堆中的資料。也就是兩個物件指向同乙個內儲存空間,無論哪個物件發生改變,其實都是改變儲存空間的內容,因此兩個物件是聯動的 var person console.log person var person1 person p...
深拷貝 淺拷貝 直接賦值
使用直接賦值後兩個物件就完全一樣,隨著改變乙個物件的值另乙個物件的值也隨之改變。淺拷貝,物件中的值型別互補影響,但是引用型別 string雖然是引用型別但特殊存在類值型別 隨著乙個物件的值改變另乙個也會改變。深拷貝,兩個物件完全獨立互補影響 1 class program212 13 1415 pu...
直接賦值 淺拷貝和深拷貝
我們經常使用的 student s1 newstudent student s2 s1 直接物件賦值,它只是拷貝了物件引用位址而已,並沒有在堆記憶體重新生成乙個新的物件 如下圖 上面的s1和s2引用其實都是指向堆中同乙個student例項位址。所以如果改下s1中的任何成員變數 基本型別或者引用型別 ...