• JS对象继承(6种)


    1. 原型链(父类的实例)
    2. 借用构造函数(调用超类构造函数)
    3. 组合继承(原型链和借用构造函数)
    4. 原型式继承(借助原型基于已有的对象上创建新对象)
    5. 寄生式继承(创建一个仅用于封装继承过程的函数)
    6. 寄生组合式继承(解决父类属性重写)

    ECMAScript无法实现接口继承,只支持实现继承,而且其实现继承主要依靠原型链来实现的

    原型链

    思想:利用原型让一个引用类型继承另一个引用类型的属性和方法。

     1 function A() {
     2     this.name = 'A';
     3 }
     4 A.prototype = {
     5     sayName: function() {
     6         return this.name;
     7     }
     8 };
     9 function B() {
    10     this.name = 'B';
    11 }
    12 //通过原型链继承对象A
    13 B.prototype = new A();
    14 var b = new B();
    15 debug(b.sayName());        //'B'

     

    1、 别忘记默认的原型(所有引用类型默认都继承Object,且通过原型链继承)

    2、 确定原型和实例的关系

    instanceof操作符和isPrototype()方法。

    3、 谨慎地定义方法

    给子类添加原型的方法的代码一定要放在替换原型的语句之后。

    通过原型链实现的继承时,不能使用对象字面量创建原型方法。这样会重写原型方法。

    4、 原型链问题

    1、 创建子类时不能向超类的构造函数传递参数

    2、 超类包含引用类型的属性,通过原型来实现继承时,实际上会变成另一个类型的实例,于是乎超类的实例的所有属性变成了子类的原型属性了。因而引发了共享属性问题(特别是引用类型属性)

    借用构造函数(经典继承)

    思想:在子类型构造函数的内部调用超类型构造函数。

     1 function A() {
     2     this.colors = ['red', 'blue', 'green'];
     3 }
     4 //借用构造函数实现继承
     5 function B() {
     6     A.call(this);        //把A在B的环境中执行,A与B中的this对象指向B的实例
     7 }
     8 var b = new B();
     9 b.colors.push('black');
    10 debug(b.colors);        //['red', 'blue', 'green', 'black']
    11 var b2 = new B();
    12 debug(b2.colors);    //['red', 'blue', 'green']
    13 1、    向超类中传递参数
    14 function A(name) {
    15     this.name = name;
    16 }
    17 //借用构造函数实现继承
    18 function B(name, age) {
    19     //把A在B的环境中执行,A与B中的this对象指向B的实例
    20     A.call(this, name);
    21     this.age = age;        
    22 }
    23 var b = new B('mackxu', 22);
    24 debug('我的名字是:'+b.name+" 我的年龄:"+b.age);

    2、 借用构造函数的问题

    1)  与构造函数模式一样的问题:在构造函数中定义的方法,无法共享。

    2)  更苦逼的事:在超类的原型中定义的方法,对子类不可见

    组合继承:(伪经典继承)

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

    结果:既通过在原型上定义方法实现了函数的复用,又能够保证每个实例都有它自己的属性。

    问题:无论什么情况下,都会调用两次超类型构造函数。一次在创建子类型原型时候、另一次在子类型构造函数内部。造成不得不在子类型构造函数中重写父类的属性。

    解决办法:寄生组合式继承[改写了原型链继承]

     1 function A(name) {
     2     this.name = name;
     3     this.colors = ['red', 'blue', 'green'];
     4 }
     5 A.prototype = {
     6     sayName: function() {
     7         return this.name;
     8     }
     9 }
    10 //借用构造函数实现继承超类属性
    11 function B(name, age) {
    12     //把A在B的环境中执行,A与B中的this对象指向B的实例
    13     A.call(this, name);
    14     this.age = age;        
    15 }
    16 //原型链继承超类的属性(方法和属性)
    17 B.prototype = new A();
    18 //此处不能用对象字面量赋值(原因前面已经给出)
    19 B.prototype.sayAge = function() {
    20     return this.age;
    21 }
    22 var b = new B('mackxu', 22);
    23 debug('我的名字是:'+b.sayName()+" 我的年龄:"+b.sayAge()+" 我喜欢的颜色:"+b.colors);

    原型式继承

    借助原型可以基于已有对象创建新对象

    1 function object(obj) {
    2     function F(){}
    3     F.prototype = obj;        //对其进行一次浅复制
    4     return new F();
    5 }

    寄生式继承(类寄生构造函数模式、工厂模式)

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

    function createAnother(A) {
        var clone = object(A);
        //以某种方式来增强这个对象
      clone.sayHi = function() {
        debug(‘Hi’);
    };
      return clone;
    }

    寄生组合式继承

     1 //改写原型链继承:
     2 function inheritPrototype(subType, superType) {
     3     var prototype = object(superType.prototype);    //创建对象[超类原型副本]
     4     prototype.constructor = subType;                    //增强对象
     5     subType.prototype = prototype;                    //指定对象
     6 }
     7 代码:
     8 //创建对象的一般步骤[原型式继承]
     9 function object(obj) {
    10     function F() {}
    11     F.prototype = obj;
    12     return new F();
    13 }
    14 /**
    15  * 改写原型链继承
    16  * @param {object} subType 子类构造函数
    17  * @param {object} superType  超类构造函数
    18  */
    19 function inheritPrototype(subType, superType) {
    20     var prototype = object(superType.prototype);    //创建对象[超类原型副本]
    21     prototype.constructor = subType;                //增强对象
    22     subType.prototype = prototype;                    //指定对象
    23 }
    24 function A(name) {
    25     this.name = name;
    26     this.colors = ['red', 'blue', 'green'];
    27 }
    28 A.prototype = {
    29     sayName: function() {
    30         return this.name;
    31     }
    32 }
    33 //借用构造函数实现继承超类属性
    34 function B(name, age) {
    35     //把A在B的环境中执行,A与B中的this对象指向B的实例
    36     A.call(this, name);
    37     this.age = age;        
    38 }
    39 //B.prototype = new A(); //原型链继承超类的属性(方法和属性)
    40 //寄生组合式继承
    41 inheritPrototype(B, A);
    42 //此处不能用对象字面量赋值(原因前面已经给出)
    43 B.prototype.sayAge = function() {
    44     return this.age;
    45 }
    46 var b = new B('mackxu', 22);
    47 debug('我的名字是:'+b.sayName()+" 我的年龄:"+b.sayAge()+" 我喜欢的颜色:"+b.colors);

    整理自JavaScript高级程序设计

  • 相关阅读:
    Protobuf
    CPU profiling
    转 Unicode 和 UTF-8 的区别
    Redis数据结构底层知识总结
    MySQL 加锁处理分析 ---非常牛逼
    MySQL Gap Lock问题
    利用Linux文件系统内存cache来提高性能
    Xcode7安装CocoaPods
    字符串排列组合算法
    iOS项目开发实战——学会使用TableView列表控件(四)plist读取与Section显示
  • 原文地址:https://www.cnblogs.com/mackxu/p/JS_inherit.html
Copyright © 2020-2023  润新知