对象和数组引用类型数据的拷贝方法汇总


前言

当我们对Array=>[],Object=>{}数据进行赋值操作时,不能像基本类型数据,number,string等一样直接赋值,如let a = [1,2],let b = a;此时赋值的其实是引用地址,如果改变b的值(或改变a的值),其对应的a(或b)也会相应改变,这种情况在开发时经常造成意外错误,下面是根据我的经验对这种引用类型数据赋值方法的汇总

1. Object.assign方法

let obj = {
    a:1,
    b:2,
    c: 'xiaoming'
}
let newObj = Object.assign({},obj)
newObj.a = 'wo'
console.log(obj.a) // 1 修改newObj的a属性值,原对象obj的a属性值没有改变
console.log(newObj.a) // wo

2. ES6语法扩展运算符方法

let obj = {
    a: 'xiaoming',
    b: 'xiaohong'
}
let obj1 = {...obj}
obj1.a = 'xiaofang'
console.log(obj.a)  //xiaoming 原对象obj的属性a值没有改变
console.log(obj1.a) //xiaofang

let arr = [1,3,5,6]
let newarr = [...arr]
newarr[0] = 10
console.log(arr)    // [1,3,5,6] 原数组没有变
console.log(newarr) // [10,3,5,6]


注意扩展运算符方法赋值只能是单层对象才有效,如果是多层则是浅拷贝,修改一方的值另一方也会跟着改变,例如下面例子
let object = {
    a: 1,
    b: {
        c: 1
    }
}
let newobject = {...object}
newobject.b.c = 100
console.log(object.b.c) //100 原对象也跟着改变了
console.log(newobject.b.c) //100

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

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

4. 用JSON字符串做转换

let obj = {
    a: 1,
    b: {
        c: 2
    }
}
let obj1 = JSON.parse(JSON.stringify(obj))
obj1.a = 10
obj1.b.c = 100
console.log(obj) // {a:1,b:{c:2}} 保持不变
console.log(obj1) //{a:10,b:{c:100}}

JSON字符串转换方式可以实现简单的深拷贝,如果对象中有方法等则不行

5.使用Object.create()方法

//直接使用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
}

6. jquery 有提供一个$.extend可以用来做深拷贝

let $ = require('jquery');
let obj1 = {
    a: 1,
    b: { f: { g: 1 } },
    c: [1, 2, 3]
}
let obj2 = $.extend(true, {}, obj1);
obj2.b.f.g = 100
obj2.c[0] = 10
console.log(obj1) // {a:1,b:{f:{g:1}},c:[1,2,3]} 没变
console.log(obj2) // {a:1,b:{f:{g:100}},c:[10,2,3]}

7.手动复制可以实现深拷贝

var obj1 = { a: 1, b: 2, c: 3 }
var obj2 = { a: obj1.a, b: obj1.b, c: obj1.c }
obj2.b = 100
console.log(obj1) // { a: 1, b: 2, c: 3 }  保持不变
console.log(obj2) // { a: 1, b: 100, c: 3 }

8. 还有一些第三方插件可以实现深拷贝比如lodash

9. 还有一些别的技巧可以实现比如数组的concat()方法

let arr1 = [1,2,3];
let arr2 = arr1.concat();
arr2[1] = 9;
console.log(arr1) // [1,2,3]
console.log(arr2) // [1,9,3]

或者
let arr3 = [4,5,6]
let arr4 = [].concat(arr3)
arr4[1] = 10
console.log(arr3) // [4,5,6]
console.log(arr4) // [4,10,6]

总结

这些方法都是实际工作中都可以用到的,还有一些其他方法比如递归也可以实现,大家可以试一试

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

空千古

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值