js中對(duì)象深拷貝方法總結(jié)
還經(jīng)常有一些公司要求,原生手寫實(shí)現(xiàn),這篇文章主要介紹了js中對(duì)象深拷貝方法總結(jié),需要的朋友可以參考下
快速克隆(存在數(shù)據(jù)丟失問題) – JSON.parse/stringify
如果不在對(duì)象中使用Date、functions、undefined、Infinity、RegExps、Maps、Sets、blob、FileLists、ImageDatas、或其他復(fù)雜類型,則深入克隆對(duì)象庫可以使用非常簡(jiǎn)單的一行代碼。
簡(jiǎn)單的來說有以下問題:
- 會(huì)忽略
undefined - 會(huì)忽略
symbol - 不能序列化函數(shù)
- 不能解決循環(huán)引用的對(duì)象
JSON.parse(JSON.stringify(object))
const a = {
string: 'string',
number: 123,
bool: false,
nul: null,
date: new Date(), // stringified
undef: undefined, // lost
inf: Infinity, // forced to 'null'
re: /.*/, // lost
}
console.log(a);
console.log(typeof a.date); // Date object
const clone = JSON.parse(JSON.stringify(a));
console.log(clone);
console.log(typeof clone.date); // result of .toISOString()使用第三方框架
由于克隆對(duì)象并不簡(jiǎn)單(復(fù)雜類型、循環(huán)引用、函數(shù)等),大多數(shù)主要庫都提供了克隆對(duì)象的功能。不要重新發(fā)明輪子-如果你已經(jīng)在使用一個(gè)庫,檢查它是否有對(duì)象克隆功能。例如:
- lodash
cloneDeep;可以通過lodash.cloneDeep模塊單獨(dú)導(dǎo)入,如果之前你沒使用過lodash,那么lodash是一個(gè)非常不錯(cuò)的選擇。 - AngularJS
angular.copy - jQuery –
jQuery.extend(true, { }, oldObject);.clone()只能克隆DOM
ES6
為了完整起見,請(qǐng)注意ES6提供了兩種淺拷貝機(jī)制:Object.assign()和拓展運(yùn)算符語法。它將所有可枚舉的自身屬性的值從一個(gè)對(duì)象復(fù)制到另一個(gè)對(duì)象。例如:
var A1 = {a: "2"};
var A2 = Object.assign({}, A1);
var A3 = {...A1}; // 拓展運(yùn)算符原生實(shí)現(xiàn)深拷貝
原生手寫深拷貝代碼,在面試當(dāng)中經(jīng)常遇到,雖然在實(shí)際項(xiàng)目開發(fā)中不是很常用,但大家還是需要熟練掌握手寫代碼的思想,因?yàn)檎娴拿嬖嚱?jīng)??嫉窖絶
function deepClone(obj) {
function isObject(o) {
return (typeof o === 'object' || typeof o === 'function') && o !== null
}
if (!isObject(obj)) {
throw new Error('非對(duì)象')
}
let isArray = Array.isArray(obj)
let newObj = isArray ? [...obj] : { ...obj }
Reflect.ownKeys(newObj).forEach(key => {
newObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key]
})
return newObj
}
let obj = {
a: [1, 2, 3],
b: {
c: 2,
d: 3
}
}
let newObj = deepClone(obj)
newObj.b.c = 1
console.log(obj.b.c) // 2MessageChannel
MessageChannel 也是一個(gè)可以實(shí)現(xiàn)深拷貝的方式。
function structuralClone(obj) {
return new Promise(resolve => {
const { port1, port2 } = new MessageChannel()
port2.onmessage = ev => resolve(ev.data)
port1.postMessage(obj)
})
}
var obj = {
a: 1,
b: {
c: 2
}
}
obj.b.d = obj.b
// 注意該方法是異步的
// 可以處理 undefined 和循環(huán)引用對(duì)象
const test = async () => {
const clone = await structuralClone(obj)
console.log(clone)
}
test()更多關(guān)于js中對(duì)象深拷貝方法請(qǐng)查看下面的相關(guān)鏈接
相關(guān)文章
javascript基礎(chǔ)之?dāng)?shù)據(jù)類型詳解
這篇文章主要介紹了如何理解JavaScript中的數(shù)據(jù)類型,幫助大家更好的學(xué)習(xí)JavaScript,感興趣的朋友可以了解下2021-11-11
javascript實(shí)現(xiàn)滑動(dòng)解鎖功能
這篇文章主要介紹了javascript實(shí)現(xiàn)滑動(dòng)解鎖功能的方法及示例,效果非常棒,需要的朋友可以參考下2014-12-12
javascript下for循環(huán)用法小結(jié)
javascript下for循環(huán)用法小結(jié)...2007-07-07
深入理解JavaScript系列(44):設(shè)計(jì)模式之橋接模式詳解
這篇文章主要介紹了深入理解JavaScript系列(44):設(shè)計(jì)模式之橋接模式詳解,橋接模式(Bridge)將抽象部分與它的實(shí)現(xiàn)部分分離,使它們都可以獨(dú)立地變化,需要的朋友可以參考下2015-03-03
JavaScript初學(xué)者應(yīng)注意的七個(gè)細(xì)節(jié)詳細(xì)介紹
種種語言都有它特別的地方,對(duì)于JavaScript來說,使用var就可以聲明任意類型的變量,這門腳本語言看起來很簡(jiǎn)單,然而想要寫出優(yōu)雅的代碼卻是需要不斷積累經(jīng)驗(yàn)的,接下來介紹初學(xué)者應(yīng)注意2012-12-12

