原型链
每个实例对象都有一个私有属性指向它构造函数的原型对象,该原型对象自己也有一个原型对象,层层向上直到对象的原型对象为null为止。这样就在实例和原型之间构造了一条原型链。
组合继承
组合继承(有时候也叫伪经典继承)是JavaScript中使用最多的继承模式,它综合了原型链和盗用构造函数,将两者的优点集中了起来。基本的思路是使用原型链继承原型上的属性和方法,而通过盗用构造函数继承实例属性。这样既可以把方法定义在原型上以实现重用,又可以让每个实例都有自己的属性。
function SuperType(name){
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function() {
console.log(this.name);
};
function SubType(name, age){
// 继承属性
SuperType.call(this, name);
this.age = age;
}
// 继承方法
SubType.prototype = new SuperType();
SubType.prototype.sayAge = function() {
console.log(this.age);
};
let instance1 = new SubType("Nicholas", 29);
instance1.colors.push("black");
console.log(instance1.colors); // "red,blue,green,black"
instance1.sayName(); // "Nicholas";
instance1.sayAge(); // 29
let instance2 = new SubType("Greg", 27);
console.log(instance2.colors); // "red,blue,green"
instance2.sayName(); // "Greg";
instance2.sayAge(); // 27
组合继承其实也存在效率问题。最主要的效率问题就是父类构造函数始终会被调用两次:一次在是创建子类原型时调用,另一次是在子类构造函数中调用。本质上,子类原型最终是要包含超类对象的所有实例属性,子类构造函数只要在执行时重写自己的原型就行了。
寄生式组合继承
寄生式组合继承基本思路是不通过调用父类构造函数给子类原型赋值,而是取得父类原型的一个副本。
function Rectangle (length, width) {
this.length = length
this.width = width
}
Rectangle.prototype.getArea = function() {
return this.length * this.width
}
function Square (length) {
Rectangle.call (this, length, length)
}
Square.prototype = Object.create (Rectangle.prototype, {
constructor: {
value: Square,
enumberable: false,
writable: true,
configurable: true
}
})
var square = new Square(3)
类继承
class Rectangle{
constructor(length,width){
this.length = length
this.width = width
}
getArea(){
return this.length*this.width
}
}
class Square extends Rectangle{
constructor(width){
super(width,width)
}
}
let square = new Square(5)
console.log(square.getArea()) // 25
console.log(square instanceof Rectangle) // true
class 实现继承的核心在于使用 extends 表明继承自哪个父类,并且在子类构造函数中必须调用 super