前言
当我们对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]
总结
这些方法都是实际工作中都可以用到的,还有一些其他方法比如递归也可以实现,大家可以试一试