JavaScript深拷貝與淺拷貝實(shí)現(xiàn)詳解
對(duì)于基本類(lèi)型數(shù)據(jù)
可以說(shuō)都是深拷貝。
對(duì)于引用類(lèi)型數(shù)據(jù)
對(duì)于引用類(lèi)型數(shù)據(jù),淺拷貝 后,因?yàn)闇\拷貝只拷貝了引用地址,所以?xún)蓚€(gè)對(duì)象均使用同一個(gè)引用地址,此引用地址指向同一個(gè)內(nèi)存即數(shù)據(jù)值。對(duì)其中任何一個(gè)對(duì)象操作會(huì)改變引用地址對(duì)應(yīng)的數(shù)據(jù)的值。
而 深拷貝 將一個(gè)對(duì)象從內(nèi)存中完整的拷貝一份出來(lái),從堆內(nèi)存中開(kāi)辟一個(gè)新的區(qū)域存放新對(duì)象,且修改新對(duì)象不會(huì)影響原對(duì)象。
問(wèn):解構(gòu)賦值是深拷貝還是淺拷貝?
若數(shù)組是一維數(shù)組,則可以看做是深拷貝。
let arr = [1, 2, 3]
let copyArr = [...arr]
copyArr.push(4)
console.log(arr, copyArr)

若數(shù)組是多維數(shù)組,則是淺拷貝。
let arr2 = [[1, 2, 3], [9, 0, 6]]
let copyArr2 = [...arr2]
copyArr2[0].push(77)
console.log(arr2, copyArr2)

注: 簡(jiǎn)單賦值只是復(fù)制了引用地址:
const a1 = [1, 2]; const a1Copy = a1; a1Copy[0] = 9; console.log(a1) // [9, 2] console.log(a1Copy) // [9, 2]
若不用 擴(kuò)展運(yùn)算符拷貝, ES5 中用變通方法來(lái)拷貝數(shù)組
const a1 = [1, 2]; const a1Copy = a1.concat(); a1Copy[0] = 9; a1 // [1, 2]
實(shí)現(xiàn)深拷貝
簡(jiǎn)單版
在不使用第三方庫(kù)的情況下,想要深拷貝一個(gè)對(duì)象
const newObj = JSON.parse(JSON.stringify(oldObj))
局限性:
- 無(wú)法實(shí)現(xiàn)對(duì)RegExp、Date、Set、Map等特殊對(duì)象的克隆
- 無(wú)法拷貝函數(shù)
- 會(huì)拋棄對(duì)象的constructor,所有的構(gòu)造函數(shù)會(huì)指向Object
- 對(duì)象有循環(huán)引用,會(huì)報(bào)錯(cuò)
夠用版
使用遞歸,拷貝數(shù)組或?qū)ο蟆?/p>
function deepClone(source) {
// 定義結(jié)果對(duì)象或數(shù)組
const targetObj = source.constructor === Array ? [] : {}
// 遍歷key
for (let keys in source) {
// 如果key是對(duì)象的自有屬性
// hasOwnProperty()查找一個(gè)對(duì)象是否有某個(gè)屬性,但是不會(huì)去查找它的原型鏈。
if (source.hasOwnProperty(keys)) {
// 如果是引用類(lèi)型
if (source[keys] && typeof source[keys] === 'object') {
// 遞歸
targetObj[keys] = deepClone(source[keys])
} else {
// 如果是基本類(lèi)型
targetObj[keys] = source[keys]
}
}
}
return targetObj
}- 關(guān)于其他情況,如解決循環(huán)引用、拷貝特殊對(duì)象、拷貝函數(shù)的情況不常見(jiàn),本文就不寫(xiě)解決這些問(wèn)題的代碼啦。
- 在實(shí)際開(kāi)發(fā),克隆數(shù)據(jù)還是使用第三方庫(kù)更好。
新發(fā)現(xiàn)個(gè)原生深拷貝的方法,
structuredClone
全局的 structuredClone() 方法使用結(jié)構(gòu)化克隆算法將給定的值進(jìn)行深拷貝 。
適用 H5;
Error 以及 Function 對(duì)象是不能被結(jié)構(gòu)化克隆算法復(fù)制等等缺點(diǎn)。
詳情看 MDN:傳送門(mén)
let obj = {
a: [1, 2],
b: "eee",
c: 3,
};
let cloneObj = structuredClone(obj);
cloneObj.a[0] = 10;
console.log(cloneObj.a[0]); // 10
console.log(obj.a[0]); // 1到此這篇關(guān)于JavaScript深拷貝與淺拷貝實(shí)現(xiàn)詳解的文章就介紹到這了,更多相關(guān)JS深拷貝與淺拷貝內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript 編寫(xiě)匿名函數(shù)的幾種方法
匿名函數(shù)可以有效控制變量作用域,構(gòu)造閉包 (Closure),防止對(duì)全局變量造成污染。在 JavaScript 中,編寫(xiě)匿名函數(shù),有以下幾種方法.2010-02-02
開(kāi)源免費(fèi)天氣預(yù)報(bào)接口API及全國(guó)所有地區(qū)代碼(國(guó)家氣象局提供)
這篇文章主要介紹了開(kāi)源免費(fèi)天氣預(yù)報(bào)接口API及全國(guó)所有地區(qū)代碼(國(guó)家氣象局提供)的相關(guān)資料,需要的朋友可以參考下2016-12-12
BootStrap Table后臺(tái)分頁(yè)時(shí)前臺(tái)刪除最后一頁(yè)所有數(shù)據(jù)refresh刷新后無(wú)數(shù)據(jù)問(wèn)題
這篇文章主要介紹了BootStrap Table后臺(tái)分頁(yè)時(shí)前臺(tái)刪除最后一頁(yè)所有數(shù)據(jù)refresh刷新后無(wú)數(shù)據(jù)問(wèn)題,需要的朋友可以參考下2016-12-12
JS實(shí)現(xiàn)數(shù)組去重方法總結(jié)(六種方法)
這篇文章給大家總結(jié)下JS實(shí)現(xiàn)數(shù)組去重方法(六種方法),面試中也經(jīng)常會(huì)遇到這個(gè)問(wèn)題。文中給大家引申的還有合并數(shù)組并去重的方法,感興趣的朋友跟隨腳本之家小編一起學(xué)習(xí)吧2017-07-07
JavaScript變量聲明var,let.const及區(qū)別淺析
這篇文章主要介紹了JavaScript變量聲明var,let.const及區(qū)別淺析,需要的朋友可以參考下2018-04-04
詳解JavaScript私有類(lèi)字段和TypeScript私有修飾符
這篇文章主要介紹了JavaScript私有類(lèi)字段和TypeScript私有修飾符,對(duì)私有類(lèi)感興趣的同學(xué),可以參考下2021-04-04
JavaScript中的執(zhí)行環(huán)境和作用域鏈
這篇文章主要介紹了JavaScript中的執(zhí)行環(huán)境和作用域鏈,幫助大家更好的理解和學(xué)習(xí)JavaScript,感興趣的朋友可以了解下2020-09-09
JavaScript實(shí)現(xiàn)圖片懶加載(Lazyload)
這篇文章主要介紹了JavaScript實(shí)現(xiàn)圖片懶加載(Lazyload)的相關(guān)資料,需要的朋友可以參考下2016-11-11
微信小程序 scroll-view 水平滾動(dòng)實(shí)現(xiàn)過(guò)程解析
這篇文章主要介紹了微信小程序 scroll-view 水平滾動(dòng)實(shí)現(xiàn)過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10

