function Cat() {}
Cat.prototype = new Animal();
Cat.prototype.name = 'cat';
缺点:
创建子类实例时无法向父类构造函数传参,const cat = new Cat('name');
来自原型对象的所有属性被所有实例共享,如果是引用类型则更改会影响其他子类实例;
无法实现多继承。
2.1.2 构造继承
使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类。
function Cat(name) {
Animal.call(this, name);
}
解决了原型继承的缺点1和缺点2(因为每一次都创建了新的父类实例)。缺点:
不能继承父类原型的属性与方法;
每个子类都有父类实力函数的副本,影响性能。
2.1.3 实例继承
为父类实例添加新特性,作为子类实例返回。
function Cat3(name) {
const cat = new Animal(name);
cat.age = 18 // 实例添加属性
return cat
}
缺点:
子类的实例其实是父类的实例;
不能多继承。
2.1.4 拷贝继承
为父类实例添加新特性,作为子类实例返回。
function Cat(name) {
const animal = new Animal(name);
for (let pro in animal) {
Cat.prototype[pro] = animal[pro];
}
}
缺点:
效率低,需要拷贝父类的属性;
无法获取父类不可枚举的属性。
2.1.5 组合继承
通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用。
function Cat(name) {
Animal.call(this, name);
}
Cat.prototype = new Animal();
Cat.prototype.constructor = Cat5;
缺点:
调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)。
2.1.6 寄生组合继承
通过寄生方式,砍掉父类的实例属性。
function Cat(name) {
Animal.call(this, name);
}
(function () {
// 创建一个没有实例方法的类
const Super = function () {};
// 将实例作为子类的原型
Super.prototype = Animal.prototype;
Cat.prototype = new Super();
})();
类型
原理
父类实例属性继承
父类原型属性继承
多继承
原型链继承
子类的原型是父类的实例
+
+
-
构造继承
调用父类构造函数
+
-
+
实例继承
子类实例是父类实例
+
+
-
拷贝继承
子类拷贝父类实例的属性和方法
+
+
+
组合继承
调用父类构造,子类原型是父类实例
+
+
?
寄生组合继承
/
+
+
?
2.2 ES6 Class 继承
子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用super方法,子类就得不到this对象。完整内容详见 Class 的继承。
class Point { /* ... */ }
class ColorPoint extends Point {
constructor(x, y, color) {
this.y = y // ReferenceError
super(x, y); // 调用父类的constructor(x, y)
this.color = color;
}
toString() {
return this.color + ' ' + super.toString(); // 调用父类的toString()
}
}
父类的静态方法,也会被子类继承,而父类的实例对象不能使用父类的静态方法。
class A {
static hello() {
console.log('hello world');
}
}
class B extends A {
}
B.hello(); // hello world
const b = new A();
b.hello(); // TypeError: newB.hello is not a function
继承关系说明
class A { }
class B extends A { }
console.log(B.__proto__ === A); // true
console.log(B.prototype.__proto__ === A.prototype); // true
super关键词的用法
当作函数调用时,代表父类的构造函数
class A {}
class B extends A {
constructor() {
super();
}
}