JavaScript继承

原型链继承

       function SuperType() {
           this.property = true;
       }
        //  在原型链上定义方法。
       SuperType.prototype.getSuperValue = function (){
           return this.property;
       }

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

        //  替换SubType原型,达到继承效果。
       SubType.prototype = new SuperType();

        //  开始写SubType的方法,注:SubType的方法必须写在替换SubType原型语句后
       SubType.prototype.getSubValue = function (){
           return this.subproperty;
       }

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

原型链继承的原理如期名,是利用创建父类(SuperType)的实例,并将该实例赋值给子类(SubType).prototype实现的,实质是重写子类的原型对象。

原型链继承特点:

  • 引用类型值的原型属性会被所有实例共享。
  • 在创建子类型的实例时,没办法再不影响所有对象实例的情况下向超类传递参数。
  • 即实现所有属性方法共享,但无法做到属性、方法独享

借用构造函数继承

        function SuperType() {
            this.colors = ['red','blue','green'];
        }

        function SubType() {
            //继承属性
            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      

借用构造函数继承(constructor stealing),该继承思想很简单,即在子类型构造函数的内部调用超类型构造函数即可。通过call()方法(或apply()方法也可以),实质上是在(未来将要)新创建的SubType实例的环境下调用SuperType构造函数。

借用构造函数继承特点:

  • 可以在子类型构造函数中向超类型构造函数传递参数。
  • 方法都在构造函数中定义,无法实现函数复用。
  • 超类型的原型中定义的方法对子类不可见。
  • 即实现所有属性独享,但无法做到方法继承

组合继承

        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);  //第二次调用SuperType
            this.age = age;
        }

        //继承方法
        SubType.prototype = new SuperType();  //第一次调用SuperType
        SubType.prototype.constructor = SubType;
        SubType.prototype.sayAge = function(){
            alert(this.age);
        }

        var instance1 = new SubType('Y',21);
        instance1.colors.push('black');
        alert(instance1.colors);  //red,blue,green,black
        instance1.sayName();  //Y
        instance1.sayAge();  //21

        var instance2 = new SubType('Z',22);
        alert(instance2.colors);  //red,blue,green
        instance2.sayName();  //Z
        instance2.sayAge();  //22

组合继承(combination inheritance)又叫伪经典继承,是JavaScript中最常用的继承模式。组合继承指的是将原型链继承和借用构造函数继承的技术组合到一块,从而发挥二者之长的一种继承模式。该模式通过借用构造函数继承属性,通过重新子类型prototype继承方法。

组合继承特点:

  • 实现了所有方法共享,属性独享
  • instanceof()和isprototypeOf()能够识别基于组合继承创建的对象。
  • 实现的时候调用了两次超类(父类),产生多余属性。

原型式继承

        //  工具函数,实质是对传入的对象执行一次浅拷贝。
        function object(o) {
            function F() {}
            F.prototype = o;
            return new F();
        }

        var person = {
            name:'Y',
            friends:['S','C','V'],
            say:function () {
                alert(this.friends);
            }
        };

        var anotherPerson = object(person);
        anotherPerson.name = 'G';
        anotherPerson.friends.push('R');

        var yetAnotherPerson = object(person);
        yetAnotherPerson.name = 'L';
        yetAnotherPerson.friends.push('B');

        person.friends.push('my');

        anotherPerson.say();  //S,C,V,R,B,my
        alert(person.friends);  //S,C,V,R,B,my
        
        

原型式继承是由道格拉斯·克罗克福德提出的,该模式要求你必须有一个对象可以作为另外一个对象的基础。该模式将一个对象传递给object()函数,然后再根据具体需求对得到的对象加以修改即可。

原型式继承特点:

  • 以传入object的对象为原型,拷贝一个副本并反回。
  • 做不到函数复用,导致效率低。
  • 对象的引用类型所有实例共享(person的引用类型friends不仅属于person所有,而且也会被antherPerson和yetAnotherPerson共享)。

寄生式继承

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

        function createAnother(original) {
            var clone = object(original);
            clone.sayHi = function (){
                alert(this.friends);
            };
            return clone;
        }
        var person = {
            name:'Y',
            friends:['S','C','V']
        };

        var anotherPerson = createAnother(person);
        anotherPerson.friends.push('test');
        anotherPerson.sayHi();

        var anotherPerson2 = createAnother(person);
        anotherPerson2.sayHi();

寄生式继承(parasitic)同样是由克罗克福德提出并推广而之的。该模式创建一个仅用于封装继承过程的函数,该函数的内部以某种方式增强对象,最后再像真地式它做了所有工作一样返回对象。

寄生式继承特点:

  • 做不到函数复用,导致效率低。
  • 对象的引用类型所有实例共享

寄生组合式继承

        function object(o) {
            function F() {}
            F.prototype = o;
            return new F();
        }
        
        //  将超类型的prototype浅拷贝一遍并赋值给子类型的prototype
        //  (相当于利用超类型prototype重写子类型prototype以达到继承效果)
        function inheritPrototype(subType,superType) {
            var prototype = object(superType.prototype);
            prototype.constructor = subType;
            subType.prototype = prototype;
        }

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

        var instance1 = new SubType('Y',21);
        instance1.colors.push('black');
        alert(instance1.colors);  //red,blue,green,black
        instance1.sayName();  //Y
        instance1.sayAge();  //21

        var instance2 = new SubType('Z',22);
        alert(instance2.colors);  //red,blue,green
        instance2.sayName();  //Z
        instance2.sayAge();  //22

原理如图:

寄生组合式继承解决了组合继承最大的问题——无论什么情况下,都会调用两次超类型构造函数。该模式思路是:不必为了指定子类型的原型而调用超类型的构造函数,我们所需的无非就是超类型原型的副本而已。本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。

寄生组合式继承特点:

  • 实现了所有方法共享,属性独享
  • instanceof()和isprototypeOf()能够识别基于组合继承创建的对象。

参考自《JavaScript高级程序设计》

你可能感兴趣的:(javascript)