let a = {
age: 1
}
let b = a
a.age = 2
console.log(b.age) // 2
从上面的例子可以发现,如果给一个变量赋值一个对象,那么两者的值会是同一个引用,其中一方改变,另一方也会相应改变。
解决这个问题,可以引入浅拷贝:
浅拷贝
- 可以使用
Object.assign
来解决这个问题
let a = {
age: 1
}
let b = Object.assign({}, a)
a.age = 2
console.log(b.age) // 1
- 使用ES6展开运算符
...
解决
let a = {
age: 1
}
let b = {...a}
a.age = 2
console.log(b.age) // 1
通常浅拷贝能解决大部分的问题,但是当遇到,对象里面嵌套一个对象的时候,就需要用到深拷贝了
let a = {
age: 1,
name: {
first: 'black'
}
}
let = {...a}
a.name.first = 'guyue'
console.log(b.name.first) // guyue
这样说明浅拷贝并没有对嵌套的对象生效。此时需要深拷贝上场:
深拷贝
深拷贝最简单的实现办法就是使用 JSON.parse(JSON.stringify(object))
来解决。
let a = {
age: 1,
name: {
first: 'black'
}
}
let b = JSON.parse(JSON.stringify(a))
a.name.first = 'guyue'
console.log(b.name.first) // black
但是当出现以下几种情况的时候,会出现问题:
let obj = {
a: 1,
b: {
c: 2
}
}
obj.c = obj.b
obj.d = obj.a
obj.b.c = obj.c
let newObj = JSON.parse(JSON.stringify(obj))
console.log(newObj)
// Uncaught TypeError: Converting circular structure to JSON
报错了,不能解决循环引用对象的问题。
let obj = {
age: undefined,
sex: function(){},
name: 'black'
}
let newObj = JSON.parse(JSON.stringify(obj))
console.log(newObj) // {name: "black"}
发现只拷贝了name ,而忽略了undefined和funcion。
所以,JSON.parse(JSON.stringify(obj))遇到这几种情况会出现问题:
- 不会拷贝
undefined
- 不能拷贝函数
- 不能解决循环引用的对象
- 只对自身的可枚举属性有效
- 执行后对象的 construetor 属性指向 Object
所以采用下面的方式:
- 递归拷贝
function deepCopy(target){
let copyed_objs = [];//此数组解决了循环引用和相同引用的问题,它存放已经递归到的目标对象
function _deepCopy(target){
if((typeof target !== 'object')||!target){return target;}
for(let i= 0 ;i<copyed_objs.length;i++){
if(copyed_objs[i].target === target){
return copyed_objs[i].copyTarget;
}
}
let obj = {};
if(Array.isArray(target)){
obj = [];//处理target是数组的情况
}
copyed_objs.push({target:target,copyTarget:obj})
Object.keys(target).forEach(key=>{
if(obj[key]){ return;}
obj[key] = _deepCopy(target[key]);
});
return obj;
}
return _deepCopy(target);
}
var a = {
age: 1,
name: {
first: 'black'
},
age: undefined,
sex: function(){},
}
var newObj = deepCopy(a)
newObj.name.first = 'guyue'
console.log(a) // {age: undefined, name: {first: "black"}, sex: ƒ}
console.log(newObj) // {age: undefined, name: {first: "guyue"}, sex: ƒ}
- lodash库 提供的_.defaultsDeep用来做深拷贝
var _ = require('lodash');
var obj1 = {
a: 1,
b: { f: { g: 1 } },
c: [1, 2, 3]
};
var obj2 = _.defaultsDeep(obj1);
console.log(obj1.b.f === obj2.b.f);
// false
网友评论