摘要:而在這個運算符的相關用例中,往往會涉及到其他知識點,深拷貝和淺拷貝就是其中之一。即對象的淺拷貝會對主對象的值進行拷貝,而該值有可能是一個指針,指向內存中的同一個對象。,可以看到深拷貝和淺拷貝是對復制引用類型變量而言的。
在ES6的系列文章中,基本都會提到Spread——擴展運算符(...)。而在這個運算符的相關用例中,往往會涉及到其他知識點,深拷貝和淺拷貝就是其中之一。
背景知識在討論深拷貝和淺拷貝之前,我們先看一個例子:
let a = "hi"; b = a; b = "hello"; console.log(a); // "hi" let arr1 = [1,2,3]; arr2 = arr1; arr2[0] = 0; console.log(arr1); // [0,2,3]
可以看到:為不同的js變量復制值時,結果是不同的。把字符串a的值復制給b,改變b的值不會影響a的值,而把數組arr1的值復制給arr2時,改變arr2的值,arr1的值也跟著改變了。
這是因為js存在兩種不同數據類型的值:基本類型值和引用類型值。
在訪問這兩種類型的變量時,其訪問方式是不同的。在這里,先記一下結論:
基本數據類型是按值訪問的
引用數據類型是按引用訪問的
(實際上這種說法并不嚴密,為便于理解,我們先這么記)
什么意思?
JavaScript不允許直接訪問內存中的位置,換句話說,不能直接操作對象的內存空間。
因此,在操作對象時,我們實際上是在操作對象的引用,而不是實際的對象。
從一個變量向另一個變量復制值時(不管是復制基本類型還是引用類型),都會先為這個新變量分配一個空間,然后把該值復制到新創建的這個空間里。
不同的是,在復制引用類型的值時,實際上復制過去的是一個指針,示例圖如下:
在js中,除了7種基本類型外,其他的都是引用類型,比如Object,Array,Function,所以不難理解:
let obj1 = {name:"hx",age:18}; let obj2 = obj1; obj2.age = 0; console.log(obj1); // {name:"hx",age:0}
“引用類型的值是按引用訪問的”不嚴密在:當復制保存著對象的某個變量時,操作的是對象的引用;而當為對象添加屬性時,操作的是實際的對象。 ——靈圖社區深拷貝 vs. 淺拷貝
我們先來看一下概念:
淺拷貝:
被復制對象的所有變量都含有與原來的對象相同的值,而所有的對其他對象的引用仍然指向原來的對象。即對象的淺拷貝會對主對象的值進行拷貝,而該值有可能是一個指針,指向內存中的同一個對象。深拷貝:
深拷貝不僅將原對象的各個屬性逐個復制出去,而且將原對象各個屬性所包含的對象也依次采用深復制的方法遞歸復制到新對象上。所以對一個對象的修改完全不會影響到另一個對象。
OK,可以看到深拷貝和淺拷貝是對“復制引用類型變量”而言的。事實上,也只有在引用類型中才有討論兩者區別的意義,對于基本數據類型,怎么拷都是“深拷貝”。
淺拷貝就不說了,=就是淺拷貝,那么如何實現深拷貝呢?
對于Object和Array兩種類型,我們分別舉例:
首先是assign(),看代碼:
let obj = {name:"hx",age:18}; let copyObj = Object.assign({},obj); copyObj.name = "H.Lucas"; console.log(obj); // {name:"hx", age:18}
Emm,貌似是深拷貝哈,那要是二維對象呢?
let obj = {name:"zj",attr:{age:18, nickname:"Z.Crystal"}} let copyObj = Object.assign({},obj); copyObj.attr.nickname = "erni"; console.log(obj); // {name:"zj",attr:{age:18, nickname:"erni"}}
好吧,翻車了,看來assign只能實現一維對象的深拷貝。
然后是擴展運算符...,看代碼:
let obj = {name:"hx",age:18}; let copyObj = {...obj}; copyObj.name = "H.Lucas"; console.log(obj); // {name:"hx", age:18}
嗯,深拷貝哈,也來個二維對象試試:
let obj = {name:"zj",attr:{age:18, nickname:"Z.Crystal"}} let copyObj = {...obj}; copyObj.attr.nickname = "erni"; console.log(obj); // {name:"zj",attr:{age:18, nickname:"erni"}}
好吧,也炸了,看來都實現不了多維對象的深拷貝。
不過這里還是推崇一下...,為什么?看兩段代碼:
let obj1 = {a:1,b:2} let obj2 = {b:3,c:4} // 構建一個新對象obj,值是obj1和obj2的集合 let obj = Object.assign(obj1,obj2) obj.b = 100 console.log(obj1) console.log(obj2) // {a: 1, b: 100, c: 4} // {b: 3, c: 4}
let obj1 = {a:1,b:2} let obj2 = {b:3,c:4} // 構建一個新對象obj,值是obj1和obj2的集合 let obj = {...obj1,...obj2} obj.b = 100 console.log(obj1) console.log(obj2) // {a: 1, b: 2} // {b: 3, c: 4}
在第一段代碼中,執行完Object.assign()時,obj1已經改變了,而且改變組合出來的obj時,obj1還會再改變。實際上我只想組合出一個完全獨立的obj來,可以肆意改變它,而不影響原始數據(想一下純函數的實現,以及Redux等)。
ArrayEmm,數組拷貝能想到哪些?
slice(),concat(),Array.from(),...
這里就不一個一個試了,先給出結論吧:
都只能實現一維數組的深拷貝
看個例子:
let arr1 = [1, 2], arr2 = [...arr1]; console.log(arr1); // [1, 2] console.log(arr2); // [1, 2] arr2[0] = 3; console.log(arr1); // [1, 2] console.log(arr2); // [3, 2] let arr3 = [1, 2, [3, 4]], arr4 = [...arr3]; console.log(arr3); // [1, 2, [3, 4]] console.log(arr4); // [1, 2, [3, 4]] arr4[2][1] = 5; console.log(arr3); // [1, 2, [3, 5]] console.log(arr4); // [1, 2, [3, 5]]
好吧,那js里到底有沒有不限條件的深拷貝方法呢?看下這個:
let obj1 = {x:1, y:{z:1}}; let obj2 = JSON.parse(JSON.stringify(obj1)); console.log(obj2) // {x:1, y:{z:1}} // 改一下obj2,看看會不會影響obj1 obj2.y.z = 2; console.log(obj1) // {x:1, y:{z:1}} // 可以,obj1沒有受到obj2的影響
簡單粗暴吧?不過JSON.parse(JSON.stringify())也并不是萬能的,比如對象的屬性是undefined,function()時:
let obj1 = { x: 1, y: undefined, z: () => console.log("lalala") }; let obj2 = JSON.parse(JSON.stringify(obj1)); console.log(obj2); // {x: 1} // 源對象的屬性y和z都丟失了,更別說深拷貝了
那數組呢?有沒有不限條件的深拷貝方法,哪怕有個類似的簡單粗暴的不完全體也行啊。
據了解只有一種方法,建一個空數組,然后一級一級遍歷原數組并填充到里面吧。
JavaScript有兩種數據類型:基本數據類型和引用數據類型;
基本數據類型:String,Number,Boolean,Undefined,Null,Symbol
引用數據類型:Object,Array,Function
JavaScript不允許直接訪問內存中的位置,因此我們操作的只是對象引用,而不是實際的對象;
深拷貝和淺拷貝是針對引用數據類型而言的;
JavaScript暫時還沒有實現多維數組/對象深拷貝的內置方法(還是說,有,但是我不知道。。)
對了,補充一個知識點:
有人說,我家=也可以實現一級深拷貝啊,你看:let arr1 = {a:1,b:2}; arr2 = arr1; arr2 = {a:0,b:1}; console.log(arr2); // {a:0, b:2} console.log(arr1); // {a:1, b:2}額。。不帶你這么玩的。。
arr2 = {a:0,b:1}; vs. arr2.a = 0;
這兩種操作可不是一碼事。。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/104034.html
摘要:深拷貝淺拷貝本文主要對深拷貝淺拷貝的解釋及實現做一下簡單記錄。之所以會有深拷貝與淺拷貝之分,是因為不同數據類型的數據在內存中的存儲區域不一樣。但注意,只能做一層屬性的淺拷貝。 深拷貝VS淺拷貝 本文主要對深拷貝&淺拷貝的解釋及實現做一下簡單記錄。原文鏈接,歡迎star。 之所以會有深拷貝與淺拷貝之分,是因為不同數據類型的數據在內存中的存儲區域不一樣。 堆和棧是計算機中劃分出來用來存儲的...
摘要:那么如何切斷和之間的關系呢,可以拷貝一份的數據,根據拷貝的層級不同可以分為淺拷貝和深拷貝,淺拷貝就是只進行一層拷貝,深拷貝就是無限層級拷貝。 深拷貝 vs 淺拷貝 深拷貝和淺拷貝都是針對的引用類型,JS中的變量類型分為值類型(基本類型)和引用類型;對值類型進行復制操作會對值進行一份拷貝,而對引用類型賦值,則會進行地址的拷貝,最終兩個變量指向同一份數據。 // 基本類型 var a = ...
閱讀 1211·2023-04-25 20:31
閱讀 3718·2021-10-14 09:42
閱讀 1485·2021-09-22 16:06
閱讀 2636·2021-09-10 10:50
閱讀 3524·2021-09-07 10:19
閱讀 1771·2019-08-30 15:53
閱讀 1170·2019-08-29 15:13
閱讀 2818·2019-08-29 13:20