zoukankan      html  css  js  c++  java
  • JavaScript继承

    最佳的继承范式

    寄生组合继承

    我们来看一下它的实现方式:

    function Object(o){
      var TempObject = function(){};
      TempObject.prototype = o;
      return new TempObject();
    }
    
    function inheritPrototype(subType,superType){
      subType.prototype = Object(superType.prototype);
      subType.prototype.constructor = subType;
    }
    
    function Person(name,age){
      this.name = name;
      this.age = age;
      this.hobby = ["football","swimming"];
    }
    
    Person.prototype.sayName = function(){
      console.log(this.name);
    }
    
    function Teacher(name,age,subject){
      Person.call(this,name,age);
      this.subject = subject;
    }
    
    inheritPrototype(Teacher,Person);
    
    var t1 = new Teacher("Tom","32","English");
    var t2 = new Teacher("Jane","28","Math");
    
    t1.sayName();
    t2.sayName();
    
    t1.hobby.push("cooking");
    t2.hobby.push("eat");
    
    console.log(t1.hobby);
    console.log(t2.hobby);
    console.log(Teacher.prototype.hobby);
    

    运行结果:

    Tom  
    Jane 
    Array [ "football", "swimming", "cooking" ]
    Array [ "football", "swimming", "eat" ]  
    undefined
    

    这里面结合了寄生式继承(来源于原型式继承)和组合继承,原型式继承可以以一个对象为基础,对基础对象进行浅复制,然后赋给子类。寄生式实现对原型式继承的封装,使之拓展更多的属性和方法。而组合继承解决了原型链对于原型对象全面复制父类构造函数的属性的问题(特别是引用类型,从构造函数的属性变成原型对象的属性,就共享了),同时解决了借用构造函数只能把属性和方法写入构造函数中的问题。组合继承的问题在于原型对象中有多余的属性(因为使用了原型链继承,构造函数的属性都继承在了原型中了,这个问题由原型式继承解决)。

    将上述的这些继承方式结合起来,扬长避短,就有了寄生组合继承,解决了上述所描述的问题,所以它是最佳的继承实现方式。

    这里简单分析一下:

    function Object(o){
      var TempObject = function(){};
      TempObject.prototype = o;
      return new TempObject();
    }
    
    function inheritPrototype(subType,superType){
      subType.prototype = Object(superType.prototype);
      subType.prototype.constructor = subType;
    }
    

    第一个函数Object(o)传入一个对象,在函数里面创立临时构造函数TempObject,并把对象o赋值给临时构造函数的原型TempObject.prototype,最后返回它的实例,结果是返回的实例中有一个[[prototype]]的指针指向它自身的原型对象,而且这个原型对象里面的属性就是o的属性。为了描述方便,这里我们把这个返回的实例称之为Tab(随便起的名字),用于下面的描述。

    在第二个函数中,subType.prototype = Object(superType.prototype);表示把superType的原型通过Object拷贝一份后赋值给Tab的原型对象,而subType的原型subType.prototype就等于这个实例。即subType.prototype有个[[prototype]]指针指向另外一个原型对象(即被继承的原型对象)。当然,此时subType.prototype在继承后也可以有自己方法。这个方法可以写在inheritPrototype() 里面(实现封装),也可以在这个函数外面增加自己的方法。

    最后,注意一下运行结果的最后一个结果:undefined,因为通过寄生式继承,在原型对象中,只会继承父类的原型对象,自然在里面就找不到构造函数的属性了。

    请看下面的例子(组合继承),这里就存在上述的弊端,即原型对象包含了父类构造函数的属性,它之所以能够不共享这些属性,仅仅只是因为在创建实例的时候创建了同样的属性覆盖了这些共享属性罢了。

    // 组合继承
    // 父类Person
    function Person(name,age){
      this.name = name;
      this.age = age;
      this.hobby = ["football","swimming"];
    }
    
    Person.prototype = {
      constructor:Person,
      sayName:function(){
        console.log("Hi,"+this.name);
      }
    }
    
    // 子类Teacher
    function Teacher(name,age,subject){
      Person.call(this,name,age);
      this.subject = subject;
    }
    
    Teacher.prototype = new Person();
    
    var t1 = new Teacher("Tom","32","English");
    var t2 = new Teacher("Jane","28","math");
    
    t1.sayName();
    console.log(t1.age);
    t1.hobby.push("cooking");
    console.log(t1.hobby);
    
    console.log("----------------------");
    
    t2.sayName();
    console.log(t2.age);
    t2.hobby.push("eat");
    console.log(t2.hobby);
    
    console.log(Teacher.prototype.hobby);
    

    运行结果:

    Hi,Tom
    32  
    Array [ "football", "swimming", "cooking" ]
    ----------------------  
    Hi,Jane 
    28  
    Array [ "football", "swimming", "eat" ] 
    Array [ "football", "swimming" ]
    

    注意到最后一个Array [ "football", "swimming" ],可见组合继承中的原型对象存在多余的属性(来自构造函数)。

    参考

    • 《JavaScript高级程序设计》
  • 相关阅读:
    母版中menu控件上传后出现脚本错误
    asp.net中修改网页的编码方式
    DataBinder的应用
    web服务器控件MultiView 应用
    asp:Wizard 应用
    web服务器控件PlaceHolder应用
    Gridivew里的Textbox值取不出来?
    登录控件Login的应用
    NHibernate调用存储过程
    FckEditor网页编辑器的使用总结
  • 原文地址:https://www.cnblogs.com/hlwyfeng/p/6079250.html
Copyright © 2011-2022 走看看