展开运算符...和Object.assign都是浅拷贝,常见的js方法如slice也是浅拷贝,那如何实现深拷贝呢?
// 需要递归拷贝
function deepClone(obj) {
// 如果传递的是null 那就不处理
// 函数没有引用关系
if (typeof obj !== 'object') return obj;
if (obj == null) return null;
// 处理日期和正则
if (obj instanceof RegExp) return new RegExp(obj);
if (obj instanceof Date) return new Date(obj);
// Object.prototype.toString.call(obj) === '[object Array]', 这么判断保留不了继承关系
let instance = new obj.constructor(); // 看当前实例的constructor
// 实现深拷贝
//for...in循环是 遍历对象的每一个可枚举属性,包括原型链上面的可枚举属性,
for (let key in obj) {
if(obj.hasOwnProperty(obj[key])) {
instance[key] = typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key]
}
}
return instance;
}
// 函数不需要重新拷贝
let obj = { a: { a: 1 } }
let newObj = deepClone(obj);
obj.a.a = 2;
console.log(newObj);
复制代码
思路是首先判断obj类型,null、Date对象,数组、正则、以及对象的typeof结果都是oobject, 需要单独分情况考虑。 对于null、Date对象以及正则,我们直接返回数值就可以了 对于数组,我们没有直接返回,因为数组可能有继承关系,需要保留继承关系,这个需要注意。 1)判断数组类型我们没用Object.prototype.toString.call(obj),因为它保留不了继承关系。 举例如下:
var t = [1,2]
t.__proto__={a:1}
Object.prototype.toString.call(t) ----> // "[object Array]"
t.constructor -----> // ƒ Object() { [native code] }
new t.constructor() --> objcet
复制代码
补充一下instanceof f instanceof Foo判断逻辑是: f的__proto__一层一层往上,能否对应到Foo.prototype