zoukankan      html  css  js  c++  java
  • 彻底理解Javascript原型继承

    彻底理解Javascript原型继承

     之前写过一篇Javascript继承主题的文章,这篇文章作为一篇读书笔记,分析的不够深入。

    本文试图进一步思考,争取彻底理解Javascript继承原理

    实例成员与原型成员

    举一个《高性能Javascript》书中例子

    var book={
        title :"High Performance JavaScript",
        publisher:"Yahoo!Press"
    };
    alert(book.toString());//"[object Object]"

    Javascript对象有两种类型的成员:实例成员和原型成员。实例成员存在于实例自身,原型成员则从对象的原型继承

    上述示例中,book对象有两个实例成员:title和publisher。book对象并没有定义toString()方法,但是却可以调用这一方法,这是因为toString()方法是book对象继承的一个原型成员

    book示例成员与原型成员关系如下图。当book.toString()被调用时,首先从对象实例搜索toString方法,如果没有找到,就转向搜索原型对象。通过这种方式,book可以访问他的原型所有的属性和方法。

    原型模式创建对象

    function Person(){}
    Person.prototype.name="Nicholas";
    Person.prototype.age=29;
    Person.prototype.job="Software Engineer";
    Person.prototype.sayName=function(){alert(this.name)};
    
    var person1=new Person();
    person1.sayName();//"Nicholas"
    
    var person2=new Person();
    person2.sayName();//"Nicholas"

    上述代码中,Person构造函数、原型对象和实例对象见关系如下

    将Person属性成员不再定义在原型对象上时

    function Person(name)
    {
        this.name=name;
    }
    Person.prototype.sayName=function(){alert(this.name)};
    var p1=new Person("Zhangsan");

    上述代码中,Person构造函数、原型对象和实例对象关系如下图所示

    从上面两图可以看出,当属性定义在构造函数中时,属性成员存在于实例对象中;属性定义在原型对象中时,实例对象访问这一属性,需要沿原型链查找该属性

    原型链继承

    让构造函数的原型对象等于另一个类型的实例,利用原型让一个引用类型继承另一个引用类型的属性和方法

    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 SubType();
    alert(instance.getSuperValue());//true

    代码示例中,完整原型链如下

    图中值得注意的细节是,父类SuperType的属性property存在于SuperType的实例对象中,getSuperValue方法存在于其原型对象中

    将SuperType实例对象赋给子类SubType的原型对象后,SubType原型对象prototype获得了父类的property属性

    换一种写法行不行?

    上文是通过将父类的实例对象赋给子类的原型对象,实现了继承的效果

    直接将父类的原型对象赋给子类的原型对象行不行?

    function Super()
    {
        this.attr='a';
    }
    Super.prototype.func=function(){alert('Super');};
    
    function Sub()
    {
        this.x='1';
    }
    
    Sub.prototype =Super.prototype;
    
    Sub.prototype.test=function(){alert('Sub');}
    
    var sub=new Sub();
    sub.func();//'Super'
    sub.test();//'Sub'
    
    sub.attr;//undefined
    sub.x;//1

    上述代码中,将Super.prototype直接赋给Sub.prototpye,发现对Sub类型实例对象sub,访问attr属性时,无法获取

    这就是因为attr属性定义在Super构造函数中,而不是定义在Super的原型对象上,此时Super.prototype中并没有attr属性

    假设将Super所有属性都定义在原型对象上,如下所示,这时sub实例对象是可以访问到父类的attr属性的

    但这时,Super类所有实例对象,都共享了attr属性,一个实例对attr属性的更改,会引起其他实例对象attr属性值的变更,这是应该避免的

    function Super()
    {
    }
    Super.prototype.attr='a';
    Super.prototype.func=function(){alert('Super');};
    
    function Sub()
    {
        this.x='1';
    }
    
    Sub.prototype =Super.prototype;
    
    Sub.prototype.test=function(){alert('Sub');}
    
    var sub=new Sub();
    
    sub.attr;//a
    sub.x;//1

    再换一种写法看看

    function Super()
    {
        this.attr='a';
    }
    Super.prototype.func=function(){alert('Super');};
    
    function Sub()
    {
        this.x='1';
    }
    
    Sub.prototype =Super();
    
    Sub.prototype.test=function(){alert('Sub');}
    
    var sub=new Sub();
    sub.func();
    sub.test();
    
    sub.attr;
    sub.x;

    实际上,上面代码会直接报错,提示test属性没有被定义

    原因是Sub.prototype=Super();这句代码,实际上是将Sub.prototype指向了undefined,因为Super()语句,是在以函数行驶调用Super()方法,这一调用,是没有返回值的

    经过这一调用,Sub.prototype此时已经为undefined,再为他定义test属性,自然就报错了

  • 相关阅读:
    NSMutableURLRequest,在POST方式下传递参数
    IOS开发学习笔记(2)-----UIButton 详解
    IOS开发学习笔记(1)-----UILabel 详解
    ios非UTF-8格式的网页解析
    ios 使用json
    IOS下WEBVIEW 的javascript数组与json定义 及交互
    Objective-C学习之解析XML
    iPhone HTTP获得XML并使用GDataXML解析
    PS学习笔记(05)
    PS学习笔记(04)
  • 原文地址:https://www.cnblogs.com/GongQi/p/4550226.html
Copyright © 2011-2022 走看看