通俗地讲,当我们说到Child继承自Parent时,指的是Parent上有的东西Child里面有得有,对于面向对象语言来说,继承最重要的两种“东西”便是实例方法和实例变量。
在某些语言中,继承已经内建到了语言的语法中,比如Java和C#。但是对于Javascript来说,其语言本身是不支持内建继承的(ES6之前),但是Javascript语言中有个叫prototype的概念,可以用于模拟类似于其他面向对象语言的继承机制。
在Javascript中,对于无需继承的对象来说,最好的定义方式是将对象的私有数据(比如实例变量)和类中各对象共享数据(比如方法)分离开来:
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.sayHello = function () {
console.log("Hello from " + this.name);
}
或者:
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype = {
constructor: Person,//维持prototype和constructor的双向指向约定
sayHello: function () {
console.log("Hello from " + this.name)
}
}
其中,constructor: Person
是为了使新建的prototype对象的constructor属性能够回指向Person构造函数,因为这个是Javascript在new对象的时候的默认行为,如果这种关系被破坏,在某些情况下可能导致问题。
至于继承,历史上不同的人提出了不同的继承方法,比如原型链继承,构造函数继承以及组合继承等。其中,最优雅的一种方式是“寄生组合继承”:
function Animal(name) {
this.name = name;
}
Animal.prototype.sayName = function () {
console.log(this.name)
}
function Cat(name, color) {
Animal.call(this, name);
this.color = color;
}
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;//注意,维持prototype与constructor之间的相互指向关系
Cat.prototype.sayName = function () {
Animal.prototype.sayName.call(this);
console.log(this.color);
}
var cat = new Cat("my-name", "red");
cat.sayName();
Babel在将ES6中的class编译为ES5时,也使用了这种方式。
网友评论