1.原型链
原型链作为继承的主要方法。基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。
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
上面的代码实例和原型之间的关系
instance -- > SubType.prototype --> SuperType.prototype --> Object
instance 指向SubType的原型,SubType又指向SuperType 的原型。getSuperValue()方法仍然在 SuperType.prototype中
但property则位于SubType.prototype 中。这是因为property是一个实例属性,而getSuperValue()是一个原型方法。
既然SubType.prototype 是 SuperType的实例 ,那么property肯定位于 SubType.prototype 中。
我们可以通过重写超类型的方法来覆盖超类型中的这个方法。
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
};
//重写方法
SubType.prototype.getSuperValue = function () {
return false
};
var instance = new SubType();
console.log(instance.getSuperValue()); //false
虽然原型链很强大,可以通过它来实现继承,但是还是有一些问题的。
当我们原型链中包含引用类型 时候,它会被所有实例共享。
function SuperType() {
this.colors = ["red", "blue"]
}
function SubType() {
}
SubType.prototype = new SuperType();
var instance1 = new SubType();
instance1.colors.push("black");
console.log(instance1.colors); //["red", "blue", "black"]
var instance2 = new SubType();
console.log(instance2.colors); //["red", "blue", "black"]
2.借用构造函数
借用构造函数的思想是在子类型构造函数的内部调用超类型构造函数,因为函数就是在特定环境中执行代码的对象。
所以我们可以通过apply()和call()方法在新创建的对象上执行构造函数
function SuperType() {
this.colors = ["red", "blue"]
}
function SubType() {
SuperType.call(this);
}
var instance1 = new SubType();
instance1.colors.push("black");
console.log(instance1.colors); //["red", "blue", "black"]
var instance2 = new SubType();
console.log(instance2.colors); //["red", "blue"]
我们通过call()方法在新创建的SubType实例的环境下调用了SuperType构造函数,
这样我们就会在新SubType对象上执行 SuperType()函数中定义的所有对象初始化代码。
所以每个SubType的每个实例都有自己的colors属性的副本。
传递参数
function SuperType(name) {
this.name = name;
}
function SubType() {
SuperType.call(this, "mnixu");
this.age = 20;
}
var instance1 = new SubType();
console.log(instance1.name); //"mnixu"
console.log(instance1.age); //20
如果仅仅是借用构造函数,那么也无法避免构造函数模式存在的问题--方法都在构造函数中定义,无法函数复用。而且,超类型的原型定义的方法,对子类型而言是不可见的,结果所有类型都只能使用构造函数模式。
3.组合继承
组合继承也叫做伪经典继承,指的是讲原型链和借用构造函数的技术组合到一起。
思想是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。
这样,即通过在原型上定义方法实现了继承复用,又能够保证每个实例都有他自己的属性。
function SuperType(name) {
this.name = name
this.colors = ["red", "blue"]
}
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.constructor = SubType;
SubType.prototype.sayAge = function(){
console.log(this.age)
};
var instance1 = new SubType("mnixu", 20);
instance1.colors.push("black");
console.log(instance1.colors); //["red", "blue", "black"]
instance1.sayAge(); // 20
instance1.sayName(); // "mnixu"
var instance2 = new SubType("zwj", 28);
console.log(instance2.colors); //["red", "blue"]
instance2.sayAge(); //28
instance2.sayName(); //"zwj"
组合继承避免了原型链和借用构造函数的缺陷,融合了他们的缺点,成为JavaScript中最常用的继承模式
4.原型式继承
function object(o){
function F() {};
F.prototype = o;
return new F();
}
var Person = {
name: "mnixu",
color: ["blue", "black"]
}
var anotherPerson = object(Person);
anotherPerson.name = "Greg";
anotherPerson.color.push("red")
var yetAnotherPerson = object(Person);
yetAnotherPerson.name = "zwj";
yetAnotherPerson.color.push("white")
console.log(anotherPerson.color); //["blue", "black", "red", "white"]
console.log(yetAnotherPerson.color); //["blue", "black", "red", "white"]
5.寄生式继承
寄生式继承是创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象。
最后再像真的是它做了所有工作一样返回对象。
function createAnother(original){
var clone = object(original); //通过调用函数创建一个新对象
clone.sayHi = function(){ //增强这个对象
console.log("hi")
};
return clone; //返回这个对象
}
var Person = {
name: "mnixu",
color: ["blue", "black"]
}
var anotherPerson = createAnother(Person);
anotherPerson.sayHi();
6.寄生组合式继承
组合继承虽然是javascript中最常用的继承模式,但是最大问题就是调用了两次超类型构造函数,
一次在创建子类型原型的时候,另一次是在子类型构造函数内部。
寄生组合式继承通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。
其思路创建一个超类型原型的副本。
function inheritPrototype(subType, superType){
var prototype = object(superType.prototype); //创建一个对象
prototype.constructor = subType;
subType.prototype = prototype;
}
function SuperType(name) {
this.name = name
this.colors = ["red", "blue"]
}
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)
};
这个例子的高效率体现在只调用了一次SuperType构造函数,避免了在SubType.prototype上面创建不必要的属性,并且,原型链还能保持不变。