在 JS进阶2 – 数组API:map, flatMap, reduce中我们学习了数组中比较重点和容易混淆的三个API:map, flatMap, reduce,本文将继续重点跟大家介绍JS中的第3个重点内容 – 深拷贝和浅拷贝。废话不多说,一起来看看吧!
3-深拷贝和浅拷贝
3-1 浅拷贝
- 浅拷贝:可以将对象的最外层属性全部复制,里层属性仍然是引用关系
- 实现方法有以下两种:
- for in
- Object.assign(obj1, obj);
- 具体实现请查看下面的代码示例。
3-2 深拷贝
- 实现方法有以下两种:
- obj1 = JSON.parse(JSON.stringify(obj));
- 特点:无法拷贝set和get方法,也无法拷贝Object.defineProperty定义的属性
- 利用Object的getOwnPropertyNames、getOwnPropertyDescriptor、defineProperty三个API手动实现cloneObject(target, source)方法,具体实现请查看下面的代码示例。
- 特点:完成所有不可遍历属性的拷贝,set、get方法也可以进行拷贝
- obj1 = JSON.parse(JSON.stringify(obj));
var obj = {
a: 1,
b: 2,
c: {
d: 10,
e: 20,
set f(value) {
this.a = value;
},
get f() {
return this.a
},
g: [1, 2, 3, 4, 5]
},
set f(value) {
this.a = value;
},
get f() {
return this.a
}
};
Object.defineProperty(obj, "h", {
value: 10
});
var obj1 = {};
// 以下两种都是浅拷贝:可以将对象的最外层属性全部复制,里层属性仍然是引用关系
// for(var key in obj) {
// obj1[key] = obj[key];
// }
// // Object.assign(obj1, obj);
// obj.a = 200;
// obj.c.d = 100;
// console.log(obj, obj1); // obj1.a还是1,但是obj1.c.d是100
// 深拷贝:但是无法拷贝set和get方法,也无法拷贝Object.defineProperty定义的属性
obj1 = JSON.parse(JSON.stringify(obj));
obj.c.d = 100;
console.log(obj, obj1); // obj1.c.d是10
/*
深拷贝:完成所有不可遍历属性的拷贝,set、get方法也可以进行拷贝
*/
function cloneObject(target, source) {
// 获取对象下的所有属性,包括不可遍历属性
var names = Object.getOwnPropertyNames(source);
console.log(names);
for(var i = 0; i < names.length; i++) {
var desc = Object.getOwnPropertyDescriptor(source.names[i]);
console.log(desc);
if(typeof(desc.value) === 'object' && desc.value !== null) {
var obj;
if(Array.isArray(desc.value)) {
obj = [];
}
else {
obj = {};
}
Object.defineProperty(target, names[i], {
configurable: desc.configurable, // 不可删除
enumerable: desc.enumerable, // 是否可遍历
value: obj, // 值
writable: desc.writable // 是否可写,即可修改
});
cloneObject(obj, desc.value);
}
else {
// Object.defineProperty(target, names[i], desc);
Object.defineProperty(target, names[i], {
configurable: desc.configurable,
enumerable: desc.enumerable,
value: desc.value,
writable: desc.writable
});
}
}
}
cloneObject(obj1, obj);
obj.c.g[1] = 100;
console.log(obj, obj1);