码迷,mamicode.com
首页 > 编程语言 > 详细

JavaScript - 继承

时间:2015-03-21 18:29:30      阅读:219      评论:0      收藏:0      [点我收藏+]

标签:

继承主要依靠原型链来实现。

1. 单独使用原型链

    基本概念:

    1)每个构造函数都有一个原型对象,原型对象有一个指向构造函数的指针,实例有一个指向原型对象的指针。

    2)访问某个实例属性时, 先在实例中搜索,如果没有,则沿着原型链继续搜索,若找不到,则直到原型链末端(Object的原型)才会消停。

    简单的实现如下:

function SuperType(){
    this.property = true;
}
SuperType.prototype.getSuperValue = function(){
    return this.property;
};
function SubType(){
    this.subproperty = false;
}
//继承了 SuperType
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function (){
    return this.subproperty;
};
var instance = new SubType();
alert(instance.getSuperValue()); //true

    其本质就是子类的原型是父类的实例,这样,子类原型就有了父类实例所拥有的所有方法和属性(虽然最好还是别拥有属性),并且还有指向父类原型的指针。而instance.constructor已经是父类构造方法了。像这样的关系:

技术分享

    再说说这种方式的问题。

    原型中有了属性,所有的实例都会共享该属性,而如果该属性是引用类型,那么一旦某个实例改了该属性,所有实例都会受牵连。

    还有,创建子类型实例时,不能向父类的构造函数中传参。

    鉴于此,这种方式还是不用的好。

2. 借用构造函数

    简单说,就是在子类构造函数内调用父类构造函数。

    至于调用方式,通过apply()和call()来实现。像这样:

function SuperType(name){
    this.name = name;
}
function SubType(){
    //继承了 SuperType,同时还传递了参数
    SuperType.call(this, "Nicholas");
    //实例属性
    this.age = 29;
}
var instance = new SubType();
alert(instance.name); //"Nicholas";
alert(instance.age); //29

    如果所有方法在构造函数中定义,那么这种方式再好不过了,但,基本不可能的。

3. 组合继承

    前两种方式各有利弊,扬长避短合成一种最常用的继承方式:使用原型链实现对原型属性和方法的继承,借用构造函数实现对实例属性的继承。

function SuperType(name){
    this.name = name;
    this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
    alert(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(){
    alert(this.age);
};
var instance1 = new SubType("Nicholas", 29);
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"
instance1.sayName(); //"Nicholas";
instance1.sayAge(); //29
var instance2 = new SubType("Greg", 27);
alert(instance2.colors); //"red,blue,green"
instance2.sayName(); //"Greg";
instance2.sayAge(); //27

    其实,子类的实例中都有两组colors和name属性,一组是调用SuperType 构造函数时,SubType.prototype 会得到两个属性colors和name(都是SuperType的实例属性),另一组是在SubType的构造函数中使用call()调用的SuperType构造函数,这次在新对象上增加了两个实例属性colors和name。这两个实例属性会屏蔽原型中的同名属性。像这样:

技术分享

4. 原型式继承

    说白了,就是浅复制, 类似于Object.create(),这样,每个复制体的基本类型相互独立,引用类型共享。

    主要函数如下:

function object(o){
    function F(){}
    F.prototype = o;
    return new F();
}

    eg:

var person = {
    name: "Nicholas",
    friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = object(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");
var yetAnotherPerson = object(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");
alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"

5. 寄生式继承

    就是创建一个 用于封装过程的函数,如同工厂模式。

function createAnother(original){
    var clone = object(original); //通过调用函数创建一个新对象
     clone.sayHi = function(){ //以某种方式来增强这个对象
         alert("hi");
    };
    return clone; //返回这个对象
}
var person = {
    name: "Nicholas",
    friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = createAnother(person);
anotherPerson.sayHi(); //"hi"

    个人觉得这种方式用处不大,就是为了说明下面这种方式的。

6. 寄生组合式继承

    组合继承的问题在于创建子类实例时,会两次调用父类构造函数(创建子类原型和子类构造函数内部使用call()时)。

    根本就无需为了指定子类型的原型而去调用父类型的构造方法,只要有一个父类原型的副本就可以了。如下方式:

function inheritPrototype(subType, superType){
    var prototype = object(superType.prototype); //创建对象
    prototype.constructor = subType; //增强对象
    subType.prototype = prototype; //指定对象
}

    这样,就可以使用inheritPrototype(SubType, SuperType)替换SubType.prototype = new SuperType()了。

    当然,在object()函数内部也执行了一次new操作。

function SuperType(name){
    this.name = name;
    this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
    alert(this.name);
};
function SubType(name, age){
    SuperType.call(this, name);
    this.age = age;
}
inheritPrototype(SubType, SuperType);
SubType.prototype.sayAge = function(){
    alert(this.age);
};

    这种方式避免了在子类原型中创建多余的属性。

JavaScript - 继承

标签:

原文地址:http://www.cnblogs.com/sduzhangxin/p/4355952.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!