JS面向对象编程(四):继承

1、原型链继承

  1. 原型链继承:利用原型让一个引用类型继承另外一个引用类型的属性和方法
//父类
function SuperType(){ 
    this.SuperProperty = "SuperType property"; 
} 
//子类
function SubType(){ 
    this.subProperty = "SubType property";
} 

//子类SubType继承了父类SuperType
SubType.prototype = new SuperType(); 

var instance = new SubType(); 
console.log(instance.SuperProperty) // 继承父类的SuperProperty属性
复制代码

经过建立 SuperType 的实例,并将该实例赋给SubType.prototype 来实现继承编程

  1. 全部引用类型默认都继承了 Object,而这个继承也是经过原型链实现的,SubType 继承了 SuperType,而 SuperType 继承了 Object。
console.log(instance instanceof Object); //true 
console.log(instance instanceof SuperType); //true 
console.log(instance instanceof SubType); //true 
复制代码

缺点bash

  1. 在经过原型来实现继承时,原型实际上会变成另外一个类型的实例。因而,原先的实例属性也就瓜熟蒂落地变成了如今的原型属性了。例如:
var instanceSup=new SuperType()
instanceSup.hasOwnProperty("SuperProperty")         //true

var instance=new SubType()
instance.hasOwnProperty("SuperProperty")    //false
复制代码

 SuperProperty是SuperType()的实例属性,是SubType()的原型属性app

  1. 不能在不影响全部对象实例的状况下,给父类型的构造函数传递参数

2、构造函数继承

  1. 构造函数继承:经过使用 call()或 apply()方法在子类型构造函数的内部调用父类型构造函数
function SuperType(){ 
    this.SuperProperty = "SuperType property"; 
} 
function SubType(){ 
 //继承了 SuperType 
 SuperType.call(this); 
} 
var instance = new SubType(); 
console.log(instance.SuperProperty) // "SuperType property"
复制代码
  1. SuperProperty是SuperType()的实例属性,也是SubType()实例属性
var instanceSup=new SuperType()
instanceSup.hasOwnProperty("SuperProperty")         //true

var instance=new SubType()
instance.hasOwnProperty("SuperProperty")    //false
复制代码
  1. 传递参数相对于原型链而言,借用构造函数有一个很大的优点,便可以在子类型构造函数中向父类型构造函 数传递参数。例如:
function SuperType(name){ 
    this.name = name; 
} 
function SubType(){ 
    //继承了 SuperType,同时还传递了参数
    SuperType.call(this, "lilei"); 
    //实例属性
    this.age = 26; 
} 
var instance = new SubType(); 
console.log(instance.name); //"lilei"; 
console.log(instance.age); //26 
复制代码

缺点:没法继承原型链上的属性和方法函数

3、组合继承

使用原型链实现对原型属性和方法的继承,而经过借用构造函数来实现对实例属性和方法的继承ui

function SuperType(name){ 
    this.name = name;
}
SuperType.prototype.country="China";

function SubType(name){
    //继承属性 
    SuperType.call(this,name);
}
SubType.prototype = new SuperType(); 
SubType.prototype.constructor = SubType;

var instance1 = new SuperType("lilei", 26);
var instance2 = new SubType("xiaoming", 22);
console.log(instance1.name)     // lilei
console.log(instance1.country)  // China
console.log(instance2.name)     // xiaoming
console.log(instance2.country)  // China
复制代码

优势:this

  1. 能够继承实例属性/方法,也能够继承原型属性/方法
  2. 可传参
  3. 函数可复用

缺点:spa

  子类原型上有父类的实例属性,子类实例屏蔽了子类原型上的属性;prototype

4、原型式继承

  1. 借助原型能够基于已有的对象建立新对象,同时还没必要所以建立自定义类;例如:
function object(o){
    function F(){}
    F.prototype = o;
    return new F();
}

function SuperType(){ 
    this.name = "lilei";
}
var superType = new SuperType();
var subType = object(superType);
console.log(subType.name) // "lilei"

复制代码

把SuperType实例化的对象做为参数传给object函数,函数就会返回一个新对象。这个新对象将superType做为原型。设计

  1. ECMAScript 5 经过新增 Object.create()方法规范化了原型式继承。这个方法接收两个参数:第一个做为新对象原型的对象,另外一个做为新对象定义额外属性的对象(可选) 。例如:
function SuperType(){ 
    this.name = "lilei";
}
var superType = new SuperType();

var subType = Object.create(superType,{
    age: {
        value: "12"
    }
});

console.log(superType.name)     // "lilei"
console.log(subType.name)       // "lilei"
复制代码

  额外属性都会覆盖原型对象上的同名属性code

function SuperType(){ 
    this.name = "lilei";
}
var superType = new SuperType();

var subType = Object.create(superType,{
    name: {
        value: "haimeimei"
    }
});

console.log(superType.name)     // "lilei"
console.log(subType.name)       // "haimeimei"
复制代码

优势
 直接将父类对象生成新的对象传递给子类

缺点
 引用类型值的属性始终都会共享相应的值,和使用原型模式同样

5、寄生式继承

function object(o){
    function F(){}
    F.prototype = o;
    return new F();
}
function createObject(o){
    var clone=object(o); 
    clone.sayHello = function(){
        console.log("hello");
    };
    return clone;
}
function SuperType(){ 
    this.name = "lilei";
}
var superType = new SuperType();

var subType = createObject(superType);
subType.sayHello(); //"hello"
复制代码

优势:不须要建立自定义类型
缺点:没法实现函数的复用

6、寄生组合式继承

组合继承的缺点是会调用两次父类型构造函数,子类原型上有父类的实例属性。所以咱们只要给子类原型赋父类原型的属性。

function inheritPrototype(subType, superType){
    var prototype = object(superType.prototype);
    prototype.constructor = subType;
    subType.prototype = prototype;
}
复制代码

函数内部:

  1. 将父类原型地址赋值给变量prototype。
  2. 重写原型会失去的默认的 constructor 属性,因此添加一个constructor属性。
  3. 把prototype赋值给子类型的原型。

举个栗子:

function object(o){
    function F(){}
    F.prototype = o;
    return new F();
}
function inheritPrototype(subType, superType){
    var prototype = object(superType.prototype);
    prototype.constructor = subType;
    subType.prototype = prototype;
}

function SuperType(name){ 
    this.name = name;
}
SuperType.prototype.country="China";

function SubType(name){
    SuperType.call(this,name);
}

inheritPrototype(SubType, SuperType);

SubType.prototype.country="America";

var superType = new SuperType("lilei");
var subType = new SubType("tom");

console.log(superType.name)     //"lilei"
console.log(superType.country)  //"China"
console.log(subType.name)       //"tom"
console.log(subType.country)    // "America"
复制代码

优势:解决了子类原型上有父类的实例属性问题,是引用类型最理想的继承范式
缺点:过程比较复杂

面向对象编程到此就完结啦,但愿对你们有帮助!


文章参考:

《JavaScript 高级程序设计》中文译本 第三版

相关文章
相关标签/搜索