假设有两个对象super,sub。sub继承了super。
根据原型链,只要sub的原型是super的实例,就可以实现继承。
- 当在sub实例上查找属性时,现在sub实例上找,没找到就在sub的原型上找
- 而sub的原型其实就是super的实例,所以其实就是在super实例上查找属性
- 如果在super实例上没找到的话,就继续在super的原型上查找,这样就实现了继承
function Super() {
this.name = 'Nichols';
this.colors = ['red', 'blue', 'green'];
}
Super.prototype.sayName = function () {
console.log(this.name);
}
function Sub(age) {
this.age = age;
}
Sub.prototype = new Super()
Sub.prototype.sayAge = function () {
console.log(this.age);
}
var sub1 = new Sub(23);
sub1.sayName();
// Nichols
sub1.sayAge();
// 23
console.log(sub1.colors);
// ["red", "blue", "green"]
但这样的继承有`如下几个问题:
- Sub中的
constructor
属性的指向变了,变成了指向Super。解决方式:在Sub.prototype = new Super()
之后,在sub的原型上重新定义constructor
属性,并指向sub函数
Sub.prototype = new Super();
Object.defineProperty(Sub.prototype, 'constructor', {
enumerable: false,
value: Sub
});
- Super上定义的实例属性都变成了sub原型上的属性,也就是所有sub的实例共有的属性。这样如果有一个sub的实例更改了sub原型上的属性,其他sub实例的属性都会被更改。
解决方法:在定义sub函数时,调用下super函数,而且这样还可以支持给SUper传参,给每一个sub的实例的属性值都不一样
function Super(name) {
this.name = name;
this.colors = ['red', 'blue', 'green'];
}
Super.prototype.sayName = function () {
console.log(this.name);
}
function Sub(name, age) {
Super.call(this, name);
this.age = age;
}
Sub.prototype = new Super();
Object.defineProperty(Sub.prototype, 'constructor', {
enumerable: false,
value: Sub
});
但这样的做法其实就是在sub的实例上定义了一套与原型上一样的属性,就将原型上的属性覆盖了。这样会调用两次super。