js實現(xiàn)深拷貝的幾種方法

簡單來說,深拷貝主要是將另一個對象的屬性值拷貝過來之后,另一個對象的屬性值并不受到影響,因為此時它自己在堆中開辟了自己的內(nèi)存區(qū)域,不受外界干擾。
淺拷貝主要拷貝的是對象的引用值,當(dāng)改變對象的值,另一個對象的值也會發(fā)生變化。

1.簡單深拷貝(一層淺拷貝)

①for循環(huán)拷貝

// 只復(fù)制第一層的淺拷貝
function simpleCopy(obj1) {
   var obj2 = Array.isArray(obj1) ? [] : {};
   for (let i in obj1) {
   obj2[i] = obj1[i];
  }
   return obj2;
}
var obj1 = {
   a: 1,
   b: 2,
   c: {
   d: 3
  }
}
var obj2 = simpleCopy(obj1);
obj2.a = 3;
obj2.c.d = 4;
alert(obj1.a); // 1
alert(obj2.a); // 3
alert(obj1.c.d); // 4
alert(obj2.c.d); // 4

②Object.assign()實現(xiàn)一層深拷貝

 var obj1 = {
    a: 1,
    b: 2,
    c: 3
}
var obj2 = Object.assign({}, obj1);
obj2.b = 5;
console.log(obj1.b); // 2
console.log(obj2.b); // 5

 var obj1 = {
    a: 1,
    b: 2,
    c: ['a','b','c']
}
var obj2 = Object.assign({}, obj1);
obj2.c[1] = 5;
console.log(obj1.c); // ["a", 5, "c"]
console.log(obj2.c); // ["a", 5, "c"]

③slice實現(xiàn)

// 對只有一級屬性值的數(shù)組對象使用slice
var a = [1,2,3,4];
var b = a.slice();
b[0] = 2;
alert(a); // 1,2,3,4
alert(b); // 2,2,3,4

// 對有多層屬性的數(shù)組對象使用slice
var a = [1,[1,2],3,4];
var b = a.slice();
b[1][0] = 2;
alert(a); // 1,2,2,3,4
alert(b); // 1,2,2,3,4

④使用concat()方法

 var a=[1,2,[3,4]]
 var c=[];
 var b=c.concat(a);
 b[0]=5;
 b[2][0]=6;
 console.log(b[0]);//5
 console.log(a[0])//1
 console.log(b[2][0]);//6
 console.log(a[2][0])//6

⑤es6的擴展運算符"..."

 var a=[1,2,[3,4]]
 var b=[...a];
 b[0]=5;
 b[2][0]=6
 console.log(b[0]);//5
 console.log(a[0])//1
 console.log(b[2][0]);//6
 console.log(a[2][0])//6

通過Object.create()實現(xiàn)

function deepCopy(obj) {
  var copy = Object.create(Object.getPrototypeOf(obj));
  var propNames = Object.getOwnPropertyNames(obj);

  propNames.forEach(function(name) {
    var desc = Object.getOwnPropertyDescriptor(obj, name);
    Object.defineProperty(copy, name, desc);
  });

  return copy;
}

var obj1 = { a: 1, b: {bc: 50, dc: 100, be: {bea: 1}} };
var obj2 = deepCopy(obj1);
obj2.a = 20;
obj2.b.bc = 60;
console.log(obj1.a)//1
console.log(obj2.a)//20
console.log(obj1.b.bc)//60
console.log(obj2.b.bc)//60

2.粗暴深拷貝(拋棄對象的constructor)

使用jsON.stringify和jsON.parse實現(xiàn)深拷貝:JSON.stringify把對象轉(zhuǎn)成字符串,再用JSON.parse把字符串轉(zhuǎn)成新的對象;

function deepCopy(obj1){
    let _obj = JSON.stringify(obj1);
    let obj2 = JSON.parse(_obj);
    return obj2;
}
var a = [1, [1, 2], 3, 4];
var b = deepCopy(a);
b[1][0] = 2;
alert(a); // 1,1,2,3,4
alert(b); // 2,2,2,3,4

缺陷:它會拋棄對象的constructor,深拷貝之后,不管這個對象原來的構(gòu)造函數(shù)是什么,在深拷貝之后都會變成Object;這種方法能正確處理的對象只有 Number, String, Boolean, Array, 扁平對象,也就是說,只有可以轉(zhuǎn)成JSON格式的對象才可以這樣用,像function沒辦法轉(zhuǎn)成JSON;

let obj1 = {
   fun:function(){
      alert(123);
   }
}
let obj2 = JSON.parse(JSON.stringify(obj1));
console.log(typeof obj1.fun); // function
console.log(typeof obj2.fun); // undefined

3.復(fù)雜深拷貝(相對完美)

遞歸拷貝實現(xiàn)深拷貝,解決循環(huán)引用問題

/**
 * 判斷是否是基本數(shù)據(jù)類型
 * @param value 
 */
function isPrimitive(value){
  return (typeof value === 'string' || 
  typeof value === 'number' || 
  typeof value === 'symbol' ||
  typeof value === 'boolean')
}

/**
 * 判斷是否是一個js對象
 * @param value 
 */
function isObject(value){
  return Object.prototype.toString.call(value) === "[object Object]"
}

/**
 * 深拷貝一個值
 * @param value 
 */
function cloneDeep(value){

  // 記錄被拷貝的值,避免循環(huán)引用的出現(xiàn)
  let memo = {};

  function baseClone(value){
    let res;
    // 如果是基本數(shù)據(jù)類型,則直接返回
    if(isPrimitive(value)){
      return value;
    // 如果是引用數(shù)據(jù)類型,我們淺拷貝一個新值來代替原來的值
    }else if(Array.isArray(value)){
      res = [...value];
    }else if(isObject(value)){
      res = {...value};
    }

    // 檢測我們淺拷貝的這個對象的屬性值有沒有是引用數(shù)據(jù)類型。如果是,則遞歸拷貝
    Reflect.ownKeys(res).forEach(key=>{
      if(typeof res[key] === "object" && res[key]!== null){
        //此處我們用memo來記錄已經(jīng)被拷貝過的引用地址。以此來解決循環(huán)引用的問題
        if(memo[res[key]]){
          res[key] = memo[res[key]];
        }else{
          memo[res[key]] = res[key];
          res[key] = baseClone(res[key])
        }
      }
    })
    return res;  
  }

  return baseClone(value)
}

3.ES插件lodash

import lodash from 'lodash'

var objects = [1,{ 'a': 1 }, { 'b': 2 }]; 
var deep = lodash.cloneDeep(objects);
deep[0] = 2;
deep[1].a = 2;
console.log(objects[0]);//1
console.log(deep[0]);//2
console.log(objects[1].a);//1
console.log(objects[1].a);//2
?著作權(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ù)。

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