js中的深淺拷貝問題簡析
前言
在開發(fā)過程中,偶爾會(huì)遇到這種場景,拿到一個(gè)數(shù)據(jù)后,你打算對它進(jìn)行處理,但是你又希望拷貝一份副本出來,方便數(shù)據(jù)對比和以后恢復(fù)數(shù)據(jù)。
那么這就涉及到了 JS 中對數(shù)據(jù)的深淺拷貝問題,所謂深淺拷貝,淺拷貝的意思就是,你只是復(fù)制了對象數(shù)據(jù)的引用,并沒有把內(nèi)存里的值另外復(fù)制一份,那么深拷貝就是把值完整地復(fù)制一份新的值。
下面這篇文章就對js中的深淺拷貝進(jìn)行了深入的講解,下面話不多說了,來一起看看詳細(xì)的介紹吧
問題描述:
因?yàn)樵贘avaScript中對象在賦值中存儲(chǔ)的是對象的地址(指針),所以會(huì)造成對象類型在復(fù)制過程中只復(fù)制對象的地址,從而導(dǎo)致以下問題
var people = {
name: "小明"
}
var peoplea = people;
peoplea.name = "小白";
console.log(peoplea.name)//小白
console.log(people.name)//小白
我們本來期望只改變peoplea的name,現(xiàn)在連people的name都改變了。根據(jù)情況的不同,可使用深拷貝或淺拷貝來解決。
解決方法:
我們在實(shí)現(xiàn)深淺拷貝之前,我們先看一看深、淺拷貝、賦值這三種的區(qū)別:
1、賦值
改變新對象時(shí)不管第幾層,老對象都會(huì)隨著變化。
var people = {
name: "小明",
act: ["吃飯","睡覺"]
}
var people1 = people;//賦值
people1.name = "小紅";
people1.act[1] = "打游戲";
console.log(people.name);//小紅
console.log(people.act);//["吃飯", "打游戲"]
2、淺拷貝
改變新對象第一層基本數(shù)據(jù)類型時(shí),老對象不變。有子對象時(shí),改變子對象,老對象會(huì)隨著變化。
var people = {
name: "小明",
act: ["吃飯", "睡覺"]
}
var people1 = Object.assign({}, people);//淺拷貝
people1.name = "小紅";
people1.act[1] = "打游戲";
console.log(people.name);//小明
console.log(people.act);// ["吃飯", "打游戲"]
3、深拷貝
不管改變新對象第幾層,老對象都不會(huì)隨之改變。
var people = {
name: "小明",
act: ["吃飯", "睡覺"]
}
var people1 = JSON.parse(JSON.stringify(people));//深拷貝
people1.name = "小紅";
people1.act[1] = "打游戲";
console.log(people.name);//小明
console.log(people.act);// ["吃飯", "睡覺"]
總結(jié)一下就是:
| 第一層為基本數(shù)據(jù)類型 | 多于一層含有子對象 | |
|---|---|---|
| 賦值 | 新老一起改變 | 新老一起改變 |
| 淺拷貝 | 新對象改變,老對象不變 | 新老一起改變 |
| 深拷貝 | 新對象改變,老對象不變 | 新對象改變,老對象不變 |
了解完了區(qū)別,下面介紹實(shí)現(xiàn)深淺拷貝的幾個(gè)方法。
一、淺拷貝
1、Object.assign()
官方對這個(gè)函數(shù)的介紹是:Object.assign() 方法用于將所有可枚舉屬性的值從一個(gè)或多個(gè)源對象復(fù)制到目標(biāo)對象。實(shí)際上就是會(huì)把屬性中的簡單數(shù)據(jù)類型直接復(fù)制,而對于對象屬性,只會(huì)拷貝地址(指針),上邊介紹區(qū)別時(shí)用的就是這個(gè);
var people1 = Object.assign({}, people);
需要注意的是,如果對象沒有子對象,Object.assign()實(shí)現(xiàn)的就是深拷貝。
2、展開運(yùn)算符(ES6新增)
var people = {
name: "小明",
act: ["吃飯", "睡覺"]
}
var people1 = {...people};
people1.name = "小紅";
people1.act[1] = "打游戲";
console.log(people.name);//小明
console.log(people.act);// ["吃飯", "打游戲"]
3、自己寫
var people = {
name: "小明",
act: ["吃飯", "睡覺"]
}
var people1 = shallowCopy(people);
people1.name = "小紅";
people1.act[1] = "打游戲";
console.log(people.name);//小明
console.log(people.act);// ["吃飯", "打游戲"]
function shallowCopy(obj) {
var res = {};
for (var index in obj) {
if (obj.hasOwnProperty(index)) {//不復(fù)制原型鏈上的屬性
res[index] = obj[index];
}
}
return res;
}
二、深拷貝
1、JSON.parse(JSON.stringify(obj))
上邊介紹區(qū)別時(shí)用的就是這個(gè):
var people1 = JSON.parse(JSON.stringify(people));//深拷貝
這個(gè)方法比較簡便但也存在問題
1、不能復(fù)制對象中的函數(shù)。
2、會(huì)忽略對象中的undefind。
2、lodash函數(shù)
官方介紹是:lodash是一個(gè)一致性、模塊化、高性能的 JavaScript 實(shí)用工具庫。官網(wǎng)是
www.lodashjs.com/ ,我推薦用其中的_.cloneDeep(value)方法。
ar objects = [{ "a": 1 }, { "b": 2 }];
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false
還有自己去寫一個(gè)遞歸,但是需要考慮的東西較多,不再贅述,也有用jq的$.extend()方法實(shí)現(xiàn)的,但是性能不好,這里提一下。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對腳本之家的支持。
相關(guān)文章
復(fù)選框全選與全不選操作實(shí)現(xiàn)思路
通過js簡單實(shí)現(xiàn)下復(fù)選框全選與全不選,很常用的一個(gè)操作,具體實(shí)現(xiàn)思路及代碼如下,有需求的朋友可以參考下,希望對大家有所幫助2013-08-08
JavaScript錯(cuò)誤處理和調(diào)試方法詳解
代碼審查是調(diào)試JavaScript的重要方法,因?yàn)樗试S多個(gè)開發(fā)人員一起處理代碼庫并在開發(fā)過程的早期發(fā)現(xiàn)錯(cuò)誤,這篇文章主要給大家介紹了關(guān)于JavaScript錯(cuò)誤處理和調(diào)試方法的相關(guān)資料,需要的朋友可以參考下2023-11-11
JavaScript下通過的XMLHttpRequest發(fā)送請求的代碼
JavaScript下通過的XMLHttpRequest發(fā)送請求的代碼,需要的朋友可以參考下。2011-06-06
Web componentd組件內(nèi)部事件回調(diào)及痛點(diǎn)剖析
這篇文章主要為大家介紹了Web componentd組件內(nèi)部事件回調(diào)示例及其痛點(diǎn)的剖析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2021-11-11
Javascript 實(shí)現(xiàn)匿名遞歸的實(shí)例代碼
本篇文章主要介紹了Javascript 實(shí)現(xiàn)匿名遞歸的實(shí)例代碼,利用 arguments.callee 來實(shí)現(xiàn)匿名遞歸的方式。有興趣的可以了解一下2017-05-05
Markdown-it將Markdown文本解析轉(zhuǎn)換為HTML
Markdown-it是一款強(qiáng)大的Markdown解析器,支持多種Markdown語法,并能將Markdown文本轉(zhuǎn)換為HTML,通過npm可快速安裝,并可在JavaScript項(xiàng)目中簡易調(diào)用,Markdown-it不僅支持基本Markdown語法,還擴(kuò)展了表格、腳注等高級(jí)功能,同時(shí)允許自定義配置和使用插件以增強(qiáng)功能2024-10-10
JS基于對象的特性實(shí)現(xiàn)去除數(shù)組中重復(fù)項(xiàng)功能詳解
這篇文章主要介紹了JS基于對象的特性實(shí)現(xiàn)去除數(shù)組中重復(fù)項(xiàng)功能,結(jié)合實(shí)例形式較為詳細(xì)的分析了js基于key值唯一性實(shí)現(xiàn)數(shù)組去重的具體步驟與相關(guān)操作技巧,需要的朋友可以參考下2017-11-11
js獲取html頁面節(jié)點(diǎn)方法(遞歸方式)
這篇文章主要介紹了js使用遞歸方式獲取html頁面節(jié)點(diǎn)的方法,大家可以參考使用吧2013-12-12

