[JavaScript 学习笔记] 2. 继承

继承

许多 OO 语言支持两种继承方式:接口继承和实现继承。接口继承只继承方法签名,而实现继承则继承实际的方法。如前所述,因为函数没有签名,在 ECMAScript 中没法实现接口继承。 ECMAScript 只支持实现继承,并且其实现继承主要是依靠原型链来实现。app

原型链

基本思想是:利用原型让一个引用类型继承另外一个引用类型的属性和方法。
构造函数、原型和实例的关系:每一个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。函数

jsfunction SuperType() {
    this.property = true;
}
SuperType.prototype.getSuperValue = function() {
    return this.property;
};

function SubType() {
    this.subproperty = false;
}

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

SuperType.prototype.getSubValue = function() {
    return this.subproperty;
}

var instance = new SubType();
alert(instance.getSuperValue());//true

  1. 别忘记默认的原型this

  2. 肯定原型和实例的关系spa

    jsalert(instance instanceof Object); //true
    alert(instance instanceof SuperType); //true
    alert(instance instanceof SubType); //true
    jsalert(Object.prototype.isPrototypeOf(instance));//ture
    alert(SuperType.prototype.isPrototypeOf(instance));//ture
    alert(SubType.prototype.isPrototypeOf(instance));//ture
  3. 谨慎地定义方法prototype

    给原型添加方法的代码必定要放在替换原型的语句以后。指针

    jsfunction SuperType() {
    this.property = true;
    }
    
    SuperType.protype.getSuperValue = function() {
    return this.property;
    }
    
    function SubType() {
    this.subproperty = false;
    }
    //继承了 SuperType
    SubType.prototype = new SuperType();
    //添加新方法
    SubType.prototype.getSubValue = function() {
    return this.subproperty;
    };
    //重写超类型中的方法
    SubType.prototype.getSuperValue = function() {
    return false;
    };
    
    var instance = new SubType();
    
    alert(instance.getSuperValue());//false
    jsfunction 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;
    },
    someOtherMethod = function() {
        return false;
    }
    };
    
    var instance = new SubType();
    alert(instance.getSuperValue()); //error 原型链被切断(如今的原型包含的是 Object 的实例)。

4.原型链的问题code

最主要的问题来自包含引用类型值的原型。前面已经介绍过包含引用类型值的原型属性会被全部实例共享,这也是为何要在构造函数中而不在原型对象中定义属性的缘由。
第二个问题是:在建立子类型的实例时,不能向超类型的构造函数中传递参数。实际上,应该说是没有办法在不影响全部对象实例的状况下,给炒类型的构造函数传递参数。对象

借用构造函数(伪造对象或经典继承)

即在子类型构造函数的内部调用超类型构造函数。函数只不过是在特定环境中执行代码的对象,因此可经过 apply()call() 方法也能够在(未来)新建立的对象上执行构造函数。blog

jsfunction 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"

传递参数继承

jsfunction SuperType(name) {
        this.name = name;
    }

    function SubType() {
        //继承了 SuperType,同时还传递了参数
        SuperType.call(this,"PaddingMe");

        //实例属性
        this.age = 25;
    }

    var instance = new SubType();

    alert(instance.name); //"PaddingMe"
    alert(instance.age); //25

组合继承(伪经典继承)

即将原型链和借用构造函数的方法组合在一块儿,思路为使用原型链实现对原型属性和方法的继承,而经过借用构造函数来实现对实例属性的继承。

jsfunction SuperType(name) {
        this.name = name;
        this.colors = ["red","blue","green"];
    }

    SuperType.prototype.sayName = function() {
        alert(this.name);
    }

    function SubType() {
        //继承属性
        SuperType.call(this,name);

        this.age = age;
    }

    SubType.prototype = new SuperType();
    SubType.prototype.constuctor = SubType();
    SubType.prototype.sayAge = function() {
        alert(this.age);
    }

    var instance1 = new("PaddingMe",25);
    instance1.colors.push("black");
    alert(instance1.colors); //"red,blue,green,black"
    instance1.sayName; //"PaddingMe"
    instance1.sayAge; //25


    var instance2 = new("hw",26);
    alert(instance2.colors); //"red,blue,green"
    instance2.sayName; //"hw"
    instance2.sayAge; //26

原型式继承

jsfunction object(o) {
        function F(){}
        F.prototype = o;
        return new F();
    }
    var person = {
        name : "PaddingMe";
        friends :["hw","wjj","hz"];
    }

    var antherPerson = object(person);
    antherPerson.name = "Hhb";
    antherPerson.friends.push("zxp");

    var yetAntherPerson = object(person);
    yetAntherPerson.name = "Linda";
    yetAntherPerson.friends.push("him");

    alert(person.friends)//"hw,wjj,hz,zxp,him"

ECMAScirpt 5 中新增 Object.create() 方法规范化了原型式继承。有两个参数,一个用做新对象原型的对象和(可选的)一个为新对象定义额外属性的对象。

在传入一个参数状况下,Objetc.create() 和 object() 方法的行为相同。

jsvar person = {
        name : "PaddingMe";
        friends :["hw","wjj","hz"];
    }
    var antherPerson = Object.create(person);
    antherPerson.name = "Hhb";
    antherPerson.friends.push("zxp");

    var yetAntherPerson = Object.create(person);
    yetAntherPerson.name = "Linda";
    yetAntherPerson.friends.push("him");

    alert(person.friends)//"hw,wjj,hz,zxp,him"

第二个参数与 `Object.defineProperties() 方法的第二个参数格式相同: 每一个属性都是经过本身的描述符定义的。

jsvar person = {
        name : "PaddingMe";
        friends :["hw","wjj","hz"];
    }

    var anthorPerson = Object.create(person, {
        name: {
            value:"hehe";
        }
    })

    alert(anthorPerson.name);//"hehe"

寄生式继承

即建立一个仅用于封装继承构成的函数,该函数在内部以某种方式来加强对象,最后再像真地是它作了全部工做同样返回对象。

jsfunction createAnother(original) {
        var clone = object(original); //经过调用函数建立一个新对象
        clone.sayHi = function() { //以某种方式来加强这个对象
            alert("hi");
        };
        return clone; //返回这个对象
    }

    var person = {
        name : "PaddingMe";
        friends :["hw","wjj","hz"];
    }

    var anthorPerson = createAnother(person);
    anthorPerson.sayHi();//"hi"

寄生组合式继承

jsfunction 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); //第二次调用SuperType();

    this.age = age;
}

SubType.prototype = new SuperType(); // 第一次调用SuperType();

SubType.prototype.constuctor = SubType;

SubType.prototype.sayAge = function(){
    alert(this.age);
}

所谓寄生组合式继承,即经过借用构造函数来继承属性,经过原型链的混成形式来继承方法。基本思路为:没必要为了指定子类型的原型而调用超类型的构造函数,咱们所须要的无非是超类型原型的一个副本而已。本质上,就是使用寄生式继承来继承超类型的原型,而后再将结构指定给子类型的原型。寄生组合式继承的基本模式:

jsfunction inheritPrototype(subType,superType){
        var prototype = object(superType.prototype); //建立对象
        prototype.constructor = subType; //加强对象
        subType.prototype = prototype; // 指定对象
    }
jsfunction 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); //第二次调用SuperType();

    this.age = age;
}

inheritPrototype(SubType,SuperType);

SubType.prototype.sayAge = function(){
    alert(this.age);
}
相关文章
相关标签/搜索