共计 3650 个字符,预计需要花费 10 分钟才能阅读完成。
继承 inherit
class 是对原型继承的一种语法糖的包装。那相对于原型继承,它有什么优点呢?
我们来先看一个典型的基于原型链继承的例子。部分内容来自“Javascript 高级程序设计”
function SuperType() {this.property = true;} | |
SuperType.prototype.getSuperValue = function() {return this.property;} | |
function SubType() {this.subProperty = false;} | |
SubType.prototype = new SuperType(); | |
SubType.prototype.getSubValue = function() {return this.subProperty;} | |
var instance = new SubType(); | |
console.log(instance.getSuperValue()); // true | |
console.log(instance instanceof Object); // true | |
console.log(instance instanceof SuperType); // true | |
console.log(instance instanceof SubType); // true |
问题,当包含引用类型的值。
function SuperType() {this.colors = ["red", "blue", "green"]; | |
} | |
function SubType() {} | |
SubType.prototype = new SuperType(); | |
var instance = new SubType(); | |
instance.colors.push("black"); | |
var instance1 = new SubType(); | |
instance1.colors.push("white"); | |
console.log(instance.colors); // ['red', 'blue', 'green', 'black', 'white'] | |
console.log(instance1.colors); // ['red', 'blue', 'green', 'black', 'white'] |
解决方案:
- 借用构造函数
function SuperType() {this.colors = ["red", "blue", "green"]; | |
} | |
function SubType() {SuperType.call(this); | |
} | |
SubType.prototype = new SuperType(); | |
var instance = new SubType(); | |
instance.colors.push("black"); | |
var instance1 = new SubType(); | |
instance1.colors.push("white"); | |
console.log(instance.colors); | |
console.log(instance1.colors); |
- 组合继承
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); | |
} |
- 寄生组合式继承
function object(o) {function F() {} | |
F.prototype = o; | |
return new F();} | |
function inheritPrototype(subType, superType) {let prototype = object(superType.prototype); | |
prototype.constructor = subType; | |
subType.prototype = prototype; | |
} | |
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; | |
} | |
inheritPrototype(SubType, SuperType); | |
SubType.prototype.sayAge = function() {console.log(this.age); | |
} | |
var instance = new SubType("Tom", 70); | |
instance.colors.push("black"); | |
var instance1 = new SubType("Jerry", 69); | |
instance1.colors.push("white"); | |
console.log(instance.colors); | |
console.log(instance.sayName()); | |
console.log(instance.sayAge()); | |
console.log(instance1.colors); | |
console.log(instance1.sayName()); | |
console.log(instance1.sayAge()); |
MDN 原型链继承
(欠图一张)
extends
从 es5 来说,实现对象的继承,还是相当麻烦的。而 extends 关键字的出现,使继承变得简单,原型会自动进行调整,super()/super 关键字可以访问父类的构造方法和属性。
class Animal {constructor(name) {this.name = name;} | |
speak() {console.log(this.name + 'makes a noise.'); | |
} | |
} | |
class Dog extends Animal {speak() {console.log(this.name + 'barks.'); | |
} | |
} | |
var d = new Dog('Mitzie'); | |
d.speak();// 'Mitzie barks.' |
分析:Dog 类没有构造函数,这样合理吗?
// 等价于上个类定义 | |
class Dog extends Animal {constructor(name) {super(name) | |
} | |
speak() {console.log(this.name + 'barks.'); | |
} | |
} |
super() 方法调用注意:
- 只可在以 extends 实现的派生类中的 constructor 方法中调用,在非派生类或方法中直接调用,会报错。
- 在 constructor 中访问 this 之前,一定要先调用 super(), 因为它负责初始化 this, 如果在 super() 调用之前尝试访问 this,会报错。
- 如果不想调用 super(),则唯一的方法是让类的 constructor() 返回一个对象。
类方法遮蔽
说明:派生类中的方法总会覆盖基类中的同名方法。
class Animal {constructor(name) {this.name = name;} | |
speak() {console.log(this.name + 'makes a noise.'); | |
} | |
} | |
class Dog extends Animal {speak() {console.log(this.name + 'barks.'); | |
} | |
} | |
// 基类中的 speak() 方法被覆盖 |
静态类成员继承
说明:如果基类有静态成员,那么这些静态成员在派生类中也可用。
class Animal {constructor(name) {this.name = name;} | |
speak() {console.log(this.name + 'makes a noise.'); | |
} | |
static create(name) {return new Animal(name); | |
} | |
} | |
class Dog extends Animal {speak() {console.log(this.name + 'barks.'); | |
} | |
} | |
let a1 = Animal.create("Monkey"); | |
let a2 = Dog.create("BeijinDog"); | |
console.log(a1 instanceof Animal); // true | |
console.log(a2 instanceof Animal); // true | |
console.log(a2 instanceof Dog); // false 这个是不是很意外? |
派生自表达式的类
内建对象继承
Symbol.species
constructor 中 new.target
正文完
发表至: javascript
2019-07-21