原型链继承(Prototypal inheritance)
1. [[Prototype]] (对象的属性)
- [[Prototype]] 是 对象的 隐藏 属性
- 它的值要么为 null,要么就是对另一个对象的引用
- __proto__ 是 [[Prototype]] 的 getter/setter
Object.getPrototypeOf/Object.setPrototypeOf 来取代 __proto__ 去 get/set 原型 -
这个属性在对象继承对象时用到
2. prototype (函数的属性)
- 每个 函数 都有prototype属性
- 它的值要么是一个对象,要么就是 null
- 默认的 "prototype" 是一个只有属性 constructor 的对象,属性 constructor 指向函数自身
- 如果 F.prototype 是一个对象,那么 new 操作符会使用它为新对象设置 [[Prototype]]
-
"prototype" 属性仅在设置了一个构造函数(constructor function),并通过 new 调用时,才具有这种特殊的影响。
function Parent(){
this.flag = true;
this.arr = [];
}
function Child(){}
console.log(Child.prototype.constructor);// Child
// 会修改Child.prototype的constructor指向
Child.prototype = new Parent();// 原型链继承
console.log(Child.prototype.constructor);// Parent
const child1 = new Child();
const child2 = new Child();
// 非引用类型不影响
console.log(child1.flag);// true
console.log(child2.flag);// true
child2.flag = false;
console.log(child1.flag);// true
console.log(child2.flag);// false
// 缺点1:引用数据类型共享,修改了child2的arr值,所有实例的值都改变
console.log(child1.arr);// []
console.log(child2.arr);// []
child2.arr.push(1);
console.log(child1.arr);// [1]
console.log(child2.arr);// [1]
// 缺点2:无法向Parent传参
借用构造函数继承(经典继承)
function Parent(){
this.flag = true;
this.arr = [];
}
Parent.prototype.getFlag = function(){}
function Child(){
Parent.call(this); // 借用构造函数继承
}
// 无法继承Parent prototype的方法
// 因为prototype只在new时有用
// child1只是Child的实例,而非Parent的实例
const child1 = new Child();
console.log(child1 instanceof Parent);// false
组合继承(原型链+经典)
// 缺点,调用2次父类构造函数
function Parent(){
this.flag = true;
this.arr = [];
}
Parent.prototype.getFlag = function(){}
function Child(){
// 通过经典继承继承实例属性的继承
Parent.call(this); // 借用构造函数继承
}
// 通过原型链继承prototype方法的继承
Child.prototype = new Parent();// 原型链继承
原型式继承
- 接受一个对象A
- 返回一个新对象B
- 并且B.proto --> A
// 相当于Object.create()
function createObjcet(obj) {
function F () {};
F.prototype = obj;
return new F();
}
寄生式继承
function createObjcet(obj) {
function F () {};
F.prototype = obj;
return new F();
}
function wraop(o){
var obj = createObjcet(o);
// 在原型式继承的基础上新增一些函数或属性
obj.sayName = function(){
console.log(this.name);
}
return obj;
}
寄生组合式继承(经典+原型式继承)
- 和组合继承的区别,用原型式继承代替原型链继承
function createObjcet(obj) {
function F () {};
F.prototype = obj;
return new F();
}
function Parent(){
this.flag = true;
this.arr = [];
}
Parent.prototype.getFlag = function(){}
function Child(){
// 通过经典继承继承实例属性的继承
Parent.call(this); // 借用构造函数继承
}
// 通过原型式继承prototype方法的继承
Child.prototype = createObjcet(Parent.prototype);
// 修正constructor
Child.prototype.constructor = Child;