JS继承方式

原型链继承

利用原型链让一个引用类型继承另一个引用类型的属性和方法

function SuperType () {
    this.colors = ["red","blue","green"];
}
function SubType () {
}
//SubType 继承 SuperType
SubType.prototype = new SuperType ();
var instance1 = new SubType ();
instance1.colors.push ("black");
console.log (instance1.colors);//Array(4) ["red", "blue", "green", "black"]

var instance2 = new SubType ();
console.log (instance2.colors);//Array(4) ["red", "blue", "green", "black"]

本质是重写原型对象。instance指向SubType的原型,SubType原型指向SuperType原型。SuperType包含一个数组(引用类型值)。

缺点:包含引用类型值得原型属性会被所有实例共享。在创建子类型的实例时,不能向超类型的构造函数中传递参数。

借用构造函数

在子类型构造函数的内部调用超类型构造函数,通过call()或apply()方法在新建对象上执行构造函数。

function SuperType (name) {
    this.name = name;
}
function SubType () {
    SuperType.call (this,"John");
    this.age = 22;
}
var instance = new SubType ();
console.log (instance.name);//John
console.log (instance.age);//22

缺点:无法实现函数复用

组合继承

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

function SuperType (name) {
    this.name = name;
    this.colors = ["red","black","green"]
}
SuperType.prototype.sayName = function () {
    console.log (this.name);
}
function SubType (name,age) {
    //继承属性
    SuperType.call (this,name);   //第二次调用SuperType()
    this.age = age;
}
//继承方法
SubType.prototype = new SuperType ();    //第一次调用SuperType()
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function () {
    console.log (this.age);
}
var instance1 = new SubType ("John",22);
instance1.colors.push ("yellow");
console.log (instance1.colors);//Array(4) ["red", "black", "green", "yellow"]
instance1.sayName ();//John
instance1.sayAge ();//22

var instance2 = new SubType ("Amy",20);
console.log (instance2.colors);//Array(3) ["red", "black", "green"]
instance2.sayName ();//Amy
instance2.sayAge ();//20

instance1和instance2既有自己的属性,又有相同的方法,是最常用的继承方式

缺点:调用两次超类型构造函数

原型式继承

将一个函数对象传递给object()得到一个新的实例对象,再根据需求对新对象进行修改

function object (o) {
    function F () {}
    F.prototype = o;
    return new F ();
}
var person = {
    name: "John",
    friends: ["A","B","C"]
}
var anotherPerson = object (person);
anotherPerson.name = "Jack";
anotherPerson.friends.push ("D");
console.log (person.friends);//Array(4) ["A", "B", "C", "D"]

也可通过Object.create()方法规范原型式继承,传入一个参数时与object()相同

var person = {
    name: "John",
    friends: ["A","B","C"]
}
var anotherPerson = Object.create (person);
anotherPerson.name = "Jack";
anotherPerson.friends.push ("D");
console.log (person.friends);//Array(4) ["A", "B", "C", "D"]

第二个参数制定的任何属性都会覆盖原型对象上的同名属性

var person = {
    name: "John",
    friends: ["A","B","C"]
}
var anotherPerson = Object.create (person,{
    name: {
        value: "Amy"
    }
});
console.log (anotherPerson.name);//Amy

寄生式继承

创建一个仅用于封装继承过程的函数

function object (o) {
    function F () {}
    F.prototype = o;
    return new F ();
}
function createAnother (original) {
    var clone = object (original);
    clone.sayhi = function () {
        console.log ("hi");
    }
    return clone;
}
var person = {
    name: "John",
    friends: ["A","B","C"]
}
var anotherPerson = createAnother (person);
anotherPerson.sayhi ();//hi

缺点:无法实现函数复用

寄生组合式继承

集寄生式继承和组合继承有点于一身,使用寄生式继承来继承超类型的原型,再将结果指定给子类型的原型。

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; //指定对象, => subType.prototype = superType
}
function SubType (name) {
    this.name = name;
    this.colors = ["yellow","red"];
}
SuperType.prototype.sayName = function () {
    console.log (this.name);
};
function SubType (name,age) {
    SuperType.call (this,name); //调用SuperType()
    this.age = age;
}
inheritPrototype (SubType,SuperType);
SubType.prototype.sayAge = function () {
    console.log (this.age);
}

高效率只调用一次SuperType(),原型链保持不变,能正常使用instance和isPrototypeOf()。是实现基于引用类型继承最有效的方式。

 

posted @ 2017-12-07 00:52  Tracy_yo  阅读(174)  评论(0编辑  收藏  举报