继承

许多OO语言都支持两种继承方式:接口继承和实现继承。接口继承只继承方法签名,实现继承则继承实际的方法。由于函数没有签名,在ECMAScript中无法实现接口继承。ECMAScript只支持实现继承,而且其实现继承主要是依靠原型链来实现的。实现的本质是重写原型对象,代之以一个新类型的实例。

1.原型链

    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

我们没有使用SubType默认提供的原型,而是给它换了一个新原型,这个新原型就是SuperType的实例。于是,新原型不仅具有作为一个SuperType的实例所拥有的全部属性和方法,而且其内部还有一个指针,指向了SupperType的原型。最终:instance指向SubType的原型,SubType的原型又指向SuperType的原型。getSuperValue方法仍然存在于SuperType.prototype中,但property则位于SubType.prototype中。这是因为property是一个实例属性,而getSuperValue则是一个原型方法。

另外,在通过原型链实现继承时,不能使用对象字面量创建原型方法,因为这样做就会重写原型链。(因为直接赋在了prototype上,而不是赋在了添加到prototype的某个方法上)。

问题:就像创建对象时遇到的问题一样,包含引用类型值的原型属性会被所有实例所共享,而这也正是为什么要在构造函数中,而不是在原型对象中定义属性的原因。现在,在通过原型来实现继承时,原型实际上会变成另一个类型的实例,于是,原先的实例属性也就变成了现在的原型属性了。

    function SuperType(){

        this.colors=["red","blue","green"];

    }



    function SubType(){

    }



    //继承了SuperType

    SubType.prototype = new SuperType();



    var instance1 = new SubType();

    instance1.colors.push("black");

    alert(instance1.colors);    //red,blue,green,black



    var instance2 = new SubType();

    alert(instance2.colors);    //red,blue,green,black

2.借用构造函数(伪造对象/经典继承)

基本思想:在子类型构造函数的内部调用超类型构造函数。函数只不过是在特定环境中执行代码的对象,因此通过使用apply()和call()方法也可以在(将来)新创建的对象上执行构造函数。

    function SuperType(){

        this.colors=["red","blue","green"];

    }



    function SubType(){

        //继承了SuperType

        SuperType.call(this);  //“借调”了超类型的构造函数

    }



    var instance1 = new SubType();

    instance1.colors.push("black");

    alert(instance1.colors);    //red,blue,green,black



    var instance2 = new SubType();

    alert(instance2.colors);    //red,blue,green

我们实际上是在(未来将要)新创建的SubType实例的环境下调用了SuperType构造函数,这样一来,就会在新SubType对象上执行SubType函数中定义的所有对象初始化代码。结果,SubType的每个实例就都会具有自己的colors属性的副本了。

问题:方法都在构造函数中定义,函数复用无从谈起。而且,在超类型的原型中定义的方法对子类型不可见。

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);

    instance1.sayName();

    instance1.sayAge();



    var instance2 = new SubType("Greg",27);

    alert(instance2.colors);

    instance2.sayName();

    instance2.sayAge();

 

 

你可能感兴趣的:(继承)