自己创建一个新的对象,来接受你要重新赋值或引用的对象值。如果对象属性是基本数据类型的值,复制的是基本类型的值给新对象。如果属性是引用类型的值,复制的是内存中的地址,如果其中一个对象改变了这个内存中的地址,肯定会影响另一个对象。
浅拷贝最终实现:
function shallowClone(target){
if(typeof target === 'object' && target !== null){
const cloneTarget = Array.isArray(target) ? [] : {};
for(let prop in target){
if(target.hasOwnProperty(prop)){
cloneTarget[prop] = target[prop];
}
}
return cloneTarget;
} else {
return target;
}
}
对于复杂类型的值,其在堆内存中开辟了一块内存地址,并将原有的对象完全复制过来存放。
JSON.stringify():对象的值中有function、undefined、symbol类型,经过序列化后键值会消失
拷贝Date类型会变成字符串
无法拷贝不可枚举的属性
无法拷贝对象的原型链
拷贝RegExp会变成空对象
对象中含有NaN、Infinity、-Infinity、JSON的序列化结果会变成null
无法拷贝对象的循环引用
手写递归
function deepClone(obj){
let cloneObj = {};
for(let key in obj){
if(typeof obj[key] === 'object'){
cloneObj[key] = deepClone(obj[key]);
} else {
cloneObj[key] = obj[key];
}
}
return cloneObj;
}
改进方法
深拷贝最终实现:
const isComplexDataType = obj => (typeof obj === 'object' || typeof obj === 'function') && (obj !== null);
function deepClone(obj, hash = new WeakMap()){
if(obj.constructor === Date){
return new Date(obj);
}
if(obj.constructor === RegExp){
return new RegExp(obj);
}
if(hash.has(obj)){
return hash.get(obj);
}
let allDesc = Object.getOwnPropertyDescriptors(obj);
let cloneObj = Object.create(Object.getPrototypeOf(obj),allDesc);
hash.set(obj, cloneObj);
for(let key of Reflect.ownKeys(obj)){
cloneObj[key] = (isComplexDataType(obj[key]) && typeof obj[key] !== 'function') ? deepClone(obj[key], hash) : obj[key];
}
return cloneObj;
}