继承发展史
1. 传统继承方式——原型链
Grand.prototype.lastName = 'Lee';
function Grand() {
}
var grand = new Grand();
Father.prototype = grand;
function Father() {
this.name = 'hehe';
}
var father = new Father();
Son.prototype = father;
function Son() {
}
var son = new Son();
假设我们只想让son继承Grand的原型上的lastName属性,但根据原型链,son还会继承father上的name属性。不管是不是想继承的属性都会被继承。
2. 借用构造函数
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
function Student(name, age, sex, grade) {
Person.call(this, name, age, sex);
this.grade = grade;
}
var stu = new Student();
使用call/apply来借用构造函数,并不是传统意义上的继承,不能继承借用的构造函数的原型
且虽然视觉效果上使用call/apply借用构造函数优化了代码,可每次在使用Student()构造函数创建新对象时,实际上多调用了一个Person()函数。
3. 共享原型
Father.prototype.lastName = 'Lee';
function Father() {
}
function Son() {
}
Son.prototype = Father.prototype;
将Father的prototype直接赋值给Son的prototype,使他们俩共用一个原型。
可将此功能封装为一个函数
function inherit(Target, Origin) {
Target.prototype = Origin.prototype;
}
Father.prototype.lastName = 'Lee';
function Father() {
}
function Son() {
}
inherit(Son, Father);
var son = new Son();
可因为共用原型,所以无法再给自身原型添加特有属性。
4. 圣杯模式
将原型链与共享原型两种方式进行结合,得出这种新的模式
新建一个构造函数
function F() {}
使F与Father共享原型,即 F.prototype = Father.prototype;
使Son.prototype = new F();
此时,Son.prototype.__proto__ = F.prototype;
而,F.prototype = Father.prototype;
所以能通过原型链继承Father.prototype上的属性
var son = new Son();
son.__proto__-->new F()-->new F().__proto__-->Father.prototype
而这时,修改Son.prototype上的属性,并不会影响到Father.prototype。
Father.prototype.lastName = 'Lee';
function Father() {
}
function Son() {
}
function inherit(Target, Origin) {
function F() {}
F.prototype = Origin.prototype;
Target.prototype = new F();
}
inherit(Son, Father);
var son = new Son();
var father = new Father();
Son.prototype.firstName = 'Ricardo';
为防止constructor指向紊乱,通常会在inherit()中加上一条语句
Target.prototype.constructor = Target;
而有时我们希望知道,Target到底继承自谁,所以还会加上一句
Target.prototype.uber = Origin.prototype;
function inherit(Target, Origin) {
function F() {}
F.prototype = Origin.prototype;
Target.prototype = new F();
Target.prototype.constructor = Target;
Target.prototype.uber = Origin.prototype;
}