前言
前言
总所周知, 实现深拷贝最知名的两种方案:JSON.parse(JSON.stringify()) 和 递归拷贝
JSON拷贝会破坏原型链结构,导致拷贝后的自定义对象实例无法使用类的静态方法(非内置对象)
下面先进行测试(请略过),再改造
JSON深拷贝原型链测试
-
创建Person类
class Person { constructor(uname, uage) { this.uname = uname this.uage = uage } } -
创建person实例,测试原型指向
const person = new Person('zhangsan', 18) console.log(person instanceof Person); // true console.log(person.__proto__ === Person.prototype) //true console.log(person.constructor === Person) // true可以看到person实例的构造器指向Person类
-
然后,我们通过JSON.parse()、JSON.stringify() 拷贝一份实例,测试原型指向
const clonePer = JSON.parse(JSON.stringify(person)) console.log(clonePer instanceof Person) // false console.log(clonePer.__proto__ === Person.prototype) // false console.log(clonePer.constructor === Person) // false console.log(clonePer.__proto__ === Object.prototype) // true console.log(clonePer.constructor === Object) // trueJSON克隆的对象原型链已经被改变, 直接指向了Object
可以看到,使用JSON克隆的对象,其原型链已经被破坏。
下面使用递归克隆测试下原型链是否被破坏。
递归深拷贝原型链测试
-
创建递归深拷贝函数
function deepClone(target) { // 对象类型 if (target instanceof Object) { let newObj = {} // new Object()的语法糖, 破坏原型链的罪魁祸首 // 处理symbol/bigint/内置对象/循环引用等,就不写了... for (const key in target) { if (Object.hasOwnProperty.call(target, key)) { newObj[key] = deepClone(target[key]) } } return newObj } else { return target } } -
使用递归克隆person实例,
const clonePer = deepClone(person); console.log(clonePer instanceof Person) // false console.log(clonePer.__proto__ === Person.prototype) // false console.log(clonePer.constructor === Person) // false console.log(clonePer.__proto__ === Object.prototype) // true console.log(clonePer.constructor === Object) // true可以发现使用new Object()创建的对象, 原型指向了Object
* 改造深拷贝函数,设置原型指向
function deepClone(target) {
// 对象类型
if (target instanceof Object) {
// 以下几种方式, 都可改变原型指向
// let newObj = {}
// Object.setPrototypeOf(newObj, target.__proto__)
// let newObj = {}
// newObj.__proto__ = target.__proto__
// let newObj = Object.create(target.__proto__);
let newObj = Reflect.construct(target.constructor, {})
// 等同于 Object.create(target.__proto__),
// Reflect更像是使用new创建的对象,不兼容IE
// 处理symbol/bigint/内置对象/循环引用等, 忽略...
for (const key in target) {
if (Object.hasOwnProperty.call(target, key)) {
newObj[key] = deepClone(target[key])
}
}
return newObj
} else {
return target
}
}
重新进行原型链测试
const clonePer = deepClone(person);
console.log(clonePer instanceof Person) // true
console.log(clonePer.__proto__ === Person.prototype) // true
console.log(clonePer.constructor === Person) // true
console.log(clonePer.__proto__ === Object.prototype) // false
console.log(clonePer.constructor === Object) // false
下面测试继承的情况:
class Person {
constructor(uname, uage) {
this.uname = uname
this.uage = uage
}
}
class Student extends Person {
constructor(uname, uage, school) {
super(uname, uage)
this.school = school
}
}
// 创建子类实例
const student = new Student('lisi', 8, '三年级一班')
// 深拷贝
const cloneStu = deepClone(student)
console.log(cloneStu instanceof Student) // true
console.log(cloneStu instanceof Person) // true
console.log(cloneStu.__proto__ === Student.prototype) // true
console.log(cloneStu.constructor === Student) // true
const proto = cloneStu.__proto__
console.log(proto.__proto__ === Person.prototype) // true
console.log(proto.__proto__.constructor === Person) // true
console.log(proto.__proto__.__proto__ === Object.prototype) // true