對象拷貝

一. 深拷貝 / 淺拷貝

1. 淺拷貝: 指針拷貝, 讓拷貝前和拷貝后對象的指針指向同一塊內(nèi)存地址
  • 增加了原對象的引用計數(shù)
  • 沒有新的內(nèi)存分配
let obj1 = {
    a: 1,
    b: 2
}
let obj2 = obj1
obj1.a = 3
console.log(obj2.a) // 3
2. 深拷貝
  • Object.assign(),只能拷貝一層, 且會改變原有對象 - ( 數(shù)組 concat 方法不會改變原有數(shù)組 )
  • ES6 擴展運算符 { ...obj },同樣只能拷貝一層
  • immutable.js 實現(xiàn),利用其不可變數(shù)據(jù)集的特性,省去深拷貝環(huán)節(jié)每次改變只影響當(dāng)前節(jié)點和它的父節(jié)點, 其他節(jié)點復(fù)用,效率高
  • lodash 庫的 cloneDeep 方法實現(xiàn)深拷貝
  • 遍歷 for in / Object.keys(obj) 遞歸, 代碼以及優(yōu)缺點如下:
1). JSON.parse(JSON.stringify()) 實現(xiàn)深拷貝的不足
    1. 如果 obj 里面有時間對象,則 JSON.stringify 后再 JSON.parse 的結(jié)果,時間將只是字符串的形式。而不是時間對象;
const obj = {
  date: new Date()
}
const newObj = JSON.parse(JSON.stringify(obj))
console.log(Object.prototype.toString.call(obj.date)) // [object Date]
console.log(Object.prototype.toString.call(newObj.date)) // [object String]
console.log(newObj.date) // 2021-04-09T02:12:31.440Z
    1. 如果 obj 里有 RegExp、Error 對象,則序列化的結(jié)果將只得到空對象;
const obj = {
  date: new Date(),
  regExp: new RegExp('\d'),
  error: new Error('error')
}
const newObj = JSON.parse(JSON.stringify(obj))
console.log(newObj.regExp) // {}
console.log(newObj.error) // {}
    1. 如果 obj 鍵名有 Symbol 或者值里有函數(shù),undefined,則序列化的結(jié)果會丟失;
const obj = {
  date: new Date(),
  regExp: new RegExp('\d'),
  error: new Error('error'),
  fn: function() {
    console.log('function')
  },
  und: undefined
}
const sym = Symbol('sym')
test[sym] = 'sym'
const newObj = JSON.parse(JSON.stringify(obj))
console.log(newObj) // {date: "2021-04-10T01:47:04.806Z", regExp: {…}, error: {…}}
    1. 如果 obj 里有 NaN、Infinity 和 -Infinity,則序列化的結(jié)果會變成 null
const obj = {
  date: new Date(),
  regExp: new RegExp('\d'),
  error: new Error('error'),
  fn: function() {
    console.log('function')
  },
  und: undefined,
  nan: NaN,
  infi: Infinity
}
const newObj = JSON.parse(JSON.stringify(obj))
console.log(Object.prototype.toString.call(obj.date))
console.log(Object.prototype.toString.call(newObj.date))
console.log(newObj.nan) // null
console.log(newObj.infi) // null
    1. JSON.stringify() 只能序列化對象的可枚舉的自有屬性,例如 如果 obj 中的對象是有構(gòu)造函數(shù)生成的, 則使用 JSON.parse(JSON.stringify(obj)) 深拷貝后,會丟棄對象的 constructor;
function Person(name) {
  this.name = name
}
const zs = new Person('zhangsan')
const obj = {
  date: new Date(),
  regExp: new RegExp('\d'),
  error: new Error('error'),
  fn: function() {
    console.log('function')
  },
  und: undefined,
  nan: NaN,
  infi: Infinity,
  zs
}
const newObj = JSON.parse(JSON.stringify(obj))
console.log(obj.zs)
console.log(newObj.zs)
compare
    1. 如果對象中存在循環(huán)引用的情況也無法正確實現(xiàn)深拷貝;
對象循環(huán)引用
2). Reflect 遞歸實現(xiàn)
function deepClone(obj) {
    // 判斷如果 obj 是基本類型數(shù)據(jù)或者函數(shù), 直接返回
    if (!obj || typeof obj !== 'object') return obj;
    if (obj instanceof Error) {
        return new Error(obj);
    }
    if (obj instanceof RegExp) {
        return new RegExp(obj);
    }
    if (obj instanceof Date) {
        return new Date(obj);
    }
    const result = Array.isArray(obj) ? [] : {};
    Reflect.ownKeys(obj).forEach(item => {
        if (obj[item] && typeof obj[item] === 'object') {
            result[item] = deepClone(obj[item]);
        } else {
            result[item] = obj[item];
        }
    })
    return result;
}
// 測試
const a = '111'
console.log(deepClone(a))
const test = {
    num: 0,
    str: '',
    boolean: true,
    unf: undefined,
    nul: null,
    obj: {
        name: '我是一個對象',
        num: 1,
        id: 1
    },
    arr: [0, 1, 2],
    func: function() {
        console.log('我是一個函數(shù)')
    },
    date: new Date(0),
    reg: new RegExp('我是一個正則', 'ig'),
    err: new Error('error')
}
const sym = Symbol('我是一個Symbol')
test[sym] = 'Symbol'
console.log(deepClone(test))
console.log(deepClone(test.date))
console.log(deepClone(test.reg))
console.log(deepClone(test.err))
Reflect_deepClone_result
  • 遞歸方法深拷貝互相引用的對象會造成棧溢出
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容