原型式继承适用一个对象的基础上再创建一个新对象,然后通过修改这个对象来实现继承
笔者认为: 原型式继承和原型链继承本质一样,都是通过重写一个构造函数的 prototype 并为 prototype 来指向一个实例,因此原型链继承有的问题,如果没有重写继承的属性,原型式它也有(如果错了欢迎指正,3ks)
function Inherit(obj) {
// 创建一个临时构造函数,
function F() {}
// 笔者看来,原型式继承和原型链继承本质相等,这里的 F 就可以理解为 子构造函数,obj 就是父元素的实例
// 将 F 的 原型 指向这个对象(将传入的对象赋值给这个构造函数的原型,对对象进行一次浅复制)
F.prototype = obj;
return new F();
}
const obj = {
name: "obj_name",
friends: ["Yohan", "Wendeer"],
sayName() {
log(this.name);
},
};
const i1 = Inherit(obj);
i1.name = "i1_name";
i1.sayName(); // log: i1_name
i1.friends.push("Zhuli"); // 更改了原型上的 friends,其他实例也跟着变化
const i2 = Inherit(obj);
i2.name = "i2_name";
i2.sayName(); // i2_name
log(i2.friends); // log: [ 'Yohan', 'Wendeer', 'Zhuli' ] 被迫新增了一个朋友
Object.create 原型式继承规范化
ts 声明: create(o: object | null, properties?: PropertyDescriptorMap & ThisType): any;
// // ts 第二个参数 键对应的配置 类型
// interface PropertyDescriptor {
// configurable?: boolean;
// enumerable?: boolean;
// value?: any;
// writable?: boolean;
// get?(): any;
// set?(v: any): void;
// }
// Object.create 将原型是规范化了
const parent = {
name: "parent_name",
friends: ["Wendeer", "Yohan"],
say() {
log(this.name);
},
};
const sonObj1 = Object.create(parent, {
name: {
value: "son_name",
},
});
sonObj1.friends.push("Zhuli");
sonObj1.say(); //log: son_name
const sonObj2 = Object.create(parent);
// 虽然规范化了,但是共享实例属性造成的问题仍然存在,除非在 Object.create 的第二个参数完全重写对应的 描述符配置
log(sonObj2.friends); // log: [ 'Wendeer', 'Yohan', 'Zhuli' ]; sonObj2 的朋友也被迫改变