帶你搞懂js的深拷貝
js深拷貝
在講正題之前我們要先瞭解數據存儲的方式
數據存儲方式
在講之前我們要先知道值類型和引用類型的存儲方式。
在JavaScript數據類型中有兩種數據類型。
值類型:字符串(String
)、數字 (Number
)、佈爾 (Boolean
)、空(Null
)、未定義(Undefined
)、Symbol
。
存放在棧內存中的簡單數據段,數據大小確定,內存空間大小可以分配。
引用數據類型:對象 (Object
) 、數組 (Array
) 、函數 (Function
) 。
存放在堆內存中的對象,在棧內存中存的是一個指針,這個指針指向堆內存一個位置。再從堆內存中取得所需的數據。
存儲如下圖:
什麼是淺/深拷貝
講完存儲的方式,我們來講講淺拷貝和深拷貝
拷貝也就是我們常常講的copy,ctrl+c,ctrl+v,那麼我們來看看例子
當我們對分別值類型和引用類型進行賦值。
var a = 5 var b = a b += 5 console.log('a=' + a,'b=' + b) var arr=[1,2,3] var brr=arr brr.push(10) console.log("arr為",arr) console.log("brr為",brr)
現象:我們發現值類型並沒有互相受到影響,然而數組(引用類型)brr數組添加元素的時候改變瞭arr數組。
解釋分析:淺拷貝隻會發生在引用類型身上,對於引用類型如果之進行簡單的賦值,隻會賦值指向堆內存的指針,這種稱為淺拷貝。而深拷貝就是完全拷貝一個引用類型,為不是地址指針。
淺拷貝看下面這張原理圖:
常用深拷貝實現
那麼我們在賦值引用類型的時候肯定不能出現淺拷貝的現象,對原數據產生影響瞭。那麼就要進行深拷貝
1.通過JSON.stringify和JSON.parse
可以深拷貝的數組和對象,但是不能拷貝函數,可以進行對象或者數組的嵌套拷貝。
缺點:無法實現對對象中方法的深拷貝
使用:
var brr=JSON.parse(JSON.stringify(arr))
例子:
var arr = { name: '浪漫主義碼農', age: 20, adress: ['jiangxi', 'changsha'], friends: { friend1: '張三', friend2: '李四' }, function(){ console.log("我是浪漫主義的對象") } } var brr=JSON.parse(JSON.stringify(arr)) brr.name='法外狂徒張三' brr.adress[0]='長沙' console.log("arr為", arr) console.log("brr為", brr)
2.擴展運算符
利用瞭對象的結構賦值特性方法。
缺點:無對對象裡面嵌套的對象進行深拷貝,相當於隻是對一層引用對象進行深拷貝
使用:
var brr={...arr}
例子:
var arr = { name: '浪漫主義碼農', age: 20, adress: ['jiangxi', 'changsha'], friends: { friend1: '張三', friend2: '李四' }, function(){ console.log("我是浪漫主義的對象") } } var brr={...arr} brr.name='法外狂徒張三' brr.adress[0]='長沙' console.log("arr為", arr) console.log("brr為", brr)
3.手寫遞歸深拷貝函數
完美解決
函數:
//使用遞歸實現深拷貝 function deepClone(obj) { //判斷拷貝的obj是對象還是數組 var objClone = Array.isArray(obj) ? [] : {}; if (obj && typeof obj === "object") { //obj不能為空,並且是對象或者是數組 因為null也是object for (key in obj) { if (obj.hasOwnProperty(key)) { if (obj[key] && typeof obj[key] === "object") { //obj裡面屬性值不為空並且還是對象,進行深度拷貝 objClone[key] = deepClone(obj[key]); //遞歸進行深度的拷貝 } else { objClone[key] = obj[key]; //直接拷貝 } } } } return objClone; }
例子:
var arr = { name: '浪漫主義碼農', age: 20, adress: ['jiangxi', 'changsha'], friends: { friend1: '張三', friend2: '李四' }, fun: function(){ console.log("我是" + this.name + "的對象") } } var brr = deepClone(arr) brr.name = '法外狂徒張三' brr.adress[0] = '長沙' console.log("arr為", arr) arr.fun() console.log("brr為", brr) brr.fun() //使用遞歸實現深拷貝 function deepClone(obj) { //判斷拷貝的obj是對象還是數組 var objClone = Array.isArray(obj) ? [] : {}; if (obj && typeof obj === "object") { //obj不能為空,並且是對象或者是數組 因為null也是object for (key in obj) { if (obj.hasOwnProperty(key)) { if (obj[key] && typeof obj[key] === "object") { //obj裡面屬性值不為空並且還是對象,進行深度拷貝 objClone[key] = deepClone(obj[key]); //遞歸進行深度的拷貝 } else { objClone[key] = obj[key]; //直接拷貝 } } } } return objClone; }
總結
本篇文章就到這裡瞭,希望能夠給你帶來幫助,也希望您能夠多多關註WalkonNet的更多內容!
推薦閱讀:
- JavaScript 賦值,淺復制和深復制的區別
- JavaScript深拷貝的幾種實現方法實例
- JS對象復制(深拷貝和淺拷貝)
- js中如何復制一個數組(淺復制、深復制)
- 詳解JSON.parse和JSON.stringify用法