深拷贝和浅拷贝实现方式

浅拷贝实现


 1. for···in只循环第一层

// 只复制第一层的浅拷贝
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


 2. Object.assign方法


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



3.使用扩展运算符实现


对于引用数据类型,扩展运算符实现的是浅拷贝。

 4.用=赋值实现

let arr1=[0,1,2,3,4],
    arr2=arr1;
console.log(arr1===arr2);
arr1[0]=1;
console.log(arr1,arr2);

 深拷贝实现


1.递归实现

function deepClone(obj){
    let objClone = Array.isArray(obj)?[]:{};
    if(obj && typeof obj==="object"){
        for(key in obj){
            if(obj.hasOwnProperty(key)){
                //判断ojb子元素是否为对象,如果是,递归复制
                if(obj[key]&&typeof obj[key] ==="object"){
                    objClone[key] = deepClone(obj[key]);
                }else{
                    //如果不是,简单复制
                    objClone[key] = obj[key];
                }
            }
        }
    }
    return objClone;
}   


2. JSON.stringify和JSON.parse实现

var   obj1 = {
   a: 1,
    b: {
      c:2
    }
   }

  var obj2 = JSON.stringify(JSON.parse(obj1)),


弊端:
1).如果obj里面有时间对象,则JSON.stringify后再JSON.parse的结果,时间将只是字符串的形式,而不是对象的形式;
2).如果obj里有RegExp(正则表达式的缩写)、Error对象,则序列化的结果将只得到空对象;
3).如果obj里有函数,undefined,则序列化的结果会把函数或 undefined丢失;
4).如果obj里有NaN、Infinity和-Infinity,则序列化的结果会变成null

5).JSON.stringify()只能序列化对象的可枚举的自有属性,例如 如果obj中的对象是有构造函数生成的, 则使用JSON.parse(JSON.stringify(obj))深拷贝后,会丢弃对象的constructor;
6).如果对象中存在循环引用的情况也无法正确实现深拷贝;


3.通过jQuery的extend方法实现深拷贝

var array = [1,2,3,4];
var newArray = $.extend(true,[],array); // true为深拷贝,false为浅拷贝


4.lodash函数库实现深拷贝

var _ = require('lodash');
var  test= {
     name:'zhangsan',
     company: { department: { name: '部门1' } },
}
  
let result = _.cloneDeep(test)


5.Reflect法

// 代理法
function deepClone(obj) {
    if (!isObject(obj)) {
        throw new Error('obj 不是一个对象!')
    }

    let isArray = Array.isArray(obj)
    let cloneObj = isArray ? [...obj] : { ...obj }
    Reflect.ownKeys(cloneObj).forEach(key => {
        cloneObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key]
    })

    return cloneObj
}


6.Object.assign ,针对对象的value是基本类型 


如果对象的value是基本类型的话,也可以用Object.assign来实现深拷贝,但是要把它赋值给一个空对象

var obj = {
    a: 1,
    b: 2
}
var obj1 = Object.assign({}, obj); // obj赋值给一个空{}
obj1.a = 3;
console.log(obj.a);// 1


7. 用slice实现对数组的深拷贝;用concat实现对数组的深拷贝(有前置条件)

Array的slice和concat方法不修改原数组,只会返回一个浅复制了原数组中的元素的一个新数组。

原数组的元素会按照下述规则拷贝:

  1. 如果该元素是个对象引用(不是实际的对象),slice 会拷贝这个对象引用到新的数组里。两个对象引用都引用了同一个对象。如果被引用的对象发生改变,则新的和原来的数组中的这个元素也会发生改变。

  2. 对于字符串、数字及布尔值来说(不是 String、Number 或者 Boolean 对象),slice 会拷贝这些值到新的数组里。在别的数组里修改这些字符串或数字或是布尔值,将不会影响另一个数组。

let arr = [1, 3, {
   username: ' kobe'
}];
let arr3 = arr.slice();
arr3[1] = 2
arr3[2].username = 'wade'
console.log(arr[1],arr3[1]);  //  3  2 
console.log(arr[2]); //  wade 
 

8 .使用扩展运算符实现(基本数据类型的拷贝)

// 当value是基本数据类型,比如String,Number,Boolean时,是可以使用拓展运算符进行深拷贝的
// 当value是引用类型的值,比如Object,Array,引用类型进行深拷贝也只是拷贝了引用地址,所以属于浅拷贝
var obj= {a: "1", b: "1", c: "2"}
var obj2= { ...obj, a: "5" }


9. 使用var newObj = Object.create(oldObj)

function deepClone(initalObj, finalObj) {    
  var obj = finalObj || {};    
  for (var i in initalObj) {        
    var prop = initalObj[i];        // 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况
    if(prop === obj) {            
      continue;
    }        
    if (typeof prop === 'object') {
      obj[i] = (prop.constructor === Array) ? [] : Object.create(prop);
    } else {
      obj[i] = prop;
    }
  }    
  return obj;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值