zoukankan      html  css  js  c++  java
  • Javascript之继承(原型链方式)

    1.原型链
    原型链是JavaScript中继承的主要方法。
    每个构造函数都拥有一个原型对象,原型对象都包含一个指向构造函数的指针(constructor),实例都包含一个指向原型对象的内部指针(__proto__)。
    假如,原型对象(Son.prototype)等于另一个类型(Pserson)的实例(person1),那么此时的原型对象(Son.prototype)将包含一个指向另一个原型(Person.prototype)的指针,相应的,另有一个原型(Person.prototype)中也包含着一个指向另一个构造函数(Person())的指针。
    再如,另一个原型(Person.prototype)又是另一个类型(Person)的实例(person1),那么上述关系依旧成立,如此层层递进,就构成了实例与原型的链条,这就是所谓的原型链。
     ​
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    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 Son(); 
    alert(instance.getSuperValue());       //true 
        
    alert(instance instanceof Object);     //true 
    alert(instance instanceof SuperType);  //true 
    alert(instance instanceof SubType);    //true

    以上代码定义了两个类型:SuperType和SubType。每个类型分别有一个属性和方法。它们主要区别就是SubType继承了SuperType,而这继承是通过创建SuperType新实例,并将这个新实例赋给SubType.prototype实现的。实现的本质就是重写原型对象,代之以新类型的实例。

     

    instance指向Subtyoe.prototype,SubType.prototype又指向了SuperType.prototype。getSuperValue()方法仍然还在SuperType。prototype中,但property则位于SubType.prototype中。这是因为property是一个实例属性,而getSyoerValue()则是一个原型方法。既然SubType.prototype现在是SuperType的实例,那么property当然位于该实例中。此外,要注意instance.constrcutor现在指向的是SuperType,这是因为原来SubType.propertype中的constructor被重写了的缘故。

    注:SubType.propertype中的constructor不被重写了的缘故,而是SubType的原型指向了另一个对象——SuperType的原型,而这个原型对象的constructor是指向SuperType的。

    通过实现原型链,本质上就是扩展了原型搜索机制。

    2.别忘了默认的原型

    事实上,我们的原型链还少了一环,所有引用类型默认继承了Object类型,而这个继承也是通过原型链实现的。我们要记住,所有函数的默认原型都是Object的实例,因此默认原型都会包含一个内部指针,指向Object.prototype。这也正式自定义类型能使用toString()等默认方法的原因。

     

    一句话,SubType集成了SuperType,而SuperType继承了Object。当调用instance.toSring()时,实际调用的是保存在Object.prototype中的那个方法。

    3.确定原型和实例的关系

    可以使用instanceof操作符来测试实例与原型链中出点过的构造函数。 

    1
    2
    3
    alert(instance instanceof Object);     //true
    alert(instance instanceof SuperType);  //true
    alert(instance instanceof SubType);    //true

    4.谨慎的定义方法

    子类型有时需要重写父类型中的某个方法,或者需要添加父类型中不穿在的某个方法,但不管怎么,给原型添加的代码一定要放在替换原型的语句之后

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    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;
        }
      
    //重写父类型中的方法
    SubType.prototype.getSuperValue=function(){
        return this.subproperty;
        }
      
    var instance=new SubType();
    alert(instance.getSuperValue());         //false

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    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;
            },
        someOtherMethod:function(){
            return false;
            }
              
        }
    var instance=new SubType();
    alert(instance.getSuperValue());         //error

    由于现在的原型包含的是一个Object的实例,而非SuperType的实例,因此我们设想中的原型链已经别切断——SubType和SuperType已经没关系了。

    5.原型链的问题

    ​原型链最主要的问题还是来支援引用类型的原型,我们以前说过包含引用类型值的原型属性会被所有实例共享,这也是为什么要在构造函数中定义属性,而不是在原型中定义属性的原因了。在通过原型来实现继承时,原型实际上会被变成另一个类型的实例。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    function SuperType(){
        this.colors=["red","blue","green"];
        }
          
    function SubType(){
    }
      
    //继承了SuperType
    SubType.prototype=new SuperType();
      
    var instance=new SubType();
    instance.colors.push("black");   //"red","blue","green","black"
    alert(instance.colors);
      
    var instance2=new SubType();
    alert(instance2.colors);          //"red","blue","green","black"

    原型的第二个问题:在创建子类的实例时,不能向父类型的构造函数草地参数,所以实践中很少单独用到原型链。





  • 相关阅读:
    角色扮演游戏引擎的设计原理
    游戏服务器架构
    小谈网络游戏同步
    What is the single most influential book every programmer should read?
    Research Scientists and Engineers
    关于为什么不推荐使用用户定义表类型的说明
    程序员必须遵守的编程原则
    CacheStrategy缓存
    正能量
    MEF 和 MAF
  • 原文地址:https://www.cnblogs.com/zxj159/p/3091572.html
Copyright © 2011-2022 走看看