zoukankan      html  css  js  c++  java
  • 原型及继承

    原型

    每个函数都有一个prototype属性,指向一个对象,这个对象专门保存特定类型的所有实例【共有的属性和方法】。

    所有原型对象都会自动获得constructor属性,指向构造函数。

    在调用构造函数创建新实例对象时,会自动设置新实例的内部属性[[Prototype]]指向构造函数的prototype属性指向的对象。

    所有对象都有[[Prototype]]属性:通过构造函数创建的对象的原型对象为构造函数的prototype属性所指的对象,通过字面量创建的对象的原型对象为Object.prototype所指向的对象。构造函数也是对象,其原型对象为Object.prototype所指向的对象。

    所有子对象共有的成员属性,都要保存在构造函数的原型对象中。即一次定义,重复使用。

     

    每当代码读取对象的某个属性时,会执行一次搜索,目标是给定名字的属性。搜索首先从对象实例本身开始。如果在实例中找到了给定的属性,则立即停止继续搜索并返回该属性的值;如果没有找到,则继续搜索指针指向的原型对象。如果在原型对象中查找到该属性,则返回该属性的值。

    实例中与原型同名的属性会屏蔽原型中的那个属性,所以不能在实例中修改原型中的属性,必须在原型上修改。

    组合使用构造函数和原型:构造函数用于定义实例属性,原型用于定义方法(引用类型)和共享的属性。这样每个实例都会获得一份自己独立的实例属性副本,彼此间互不影响。

    function Person(name, age, job) {
        this.name = name;
        this.age = age;
        this.job = job;
        this.friends = [“Shelby”, “Court”];
    }
    
    Person.prototype = {
        constructor: Person,
        sayName: function () {
            alert(this.name);
        }
    };
    
    var person1 = new Person(“Nicholas”, 29, “Software Engineer”);
    var person2 = new Person(“Greg”, 27, “Doctor”);
    person1.friends.push(“Van”);
    alert(person1.friends); //”Shelby,Court,Van”
    alert(person2.friends); //”Shelby,Court”
    alert(person1.friends === person2.friends); //false
    alert(person1.sayName === person2.sayName); //true 

    原型相关API:

    • 获取原型对象:

      从构造函数获得原型对象: 构造函数.prototype

      从子对象获得父级原型对象:

        子对象.__proto__(有兼容性问题)

              Object.getPrototypeOf({...}) === Object.prototype

    • 判断原型对象是否在实例的原型链上:

        obj.isPrototypeOf(实例)   //Array.prototype.isPrototypeOf([])判断数组

    • 自有属性和共有属性:

        obj.hasOwnProperty()     //检测一个属性是否存在于实例中。

    • in关键字:property in obj

        在obj的原型链上查找指定属性名property

    • 删除对象的属性:delete obj.property  //不能删除共有属性                       

    原型链

    本质是重写原型对象,让一个类型的原型对象等于另一个类型的实例

    function SuperType(){
        this.property = true;
    }
    
    SuperType.prototype.getSuperValue = function(){
        return this.property;
    };
    
    function SubType(){
        this.subproperty = false;
    }
    
    //重写原型对象,以新的原型对象替换默认原型,实现继承。
    //不能是父类的原型对象,只能是实例。否则子类修改原型属性时会影响父类。
    SubType.prototype = new SuperType();
    SubType.prototype.getSubValue = function (){
        return this.subproperty;
    };
    
    var instance = new SubType();
    console.log(instance.getSuperValue()); //true

    继承的实现

    1. 单个继承

             Object.create(Proto [,propertiesObject]);  // 使用指定的原型对象和属性创建一个新对象。

    等价于:

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

      Object.setPrototypeOf(Plane.prototype,Flyer.prototype);  //Plane.prototype.__proto__=Flyer.prototype;

      //直接设置一个对象的内部[[Prototype]]属性到另一个对象或null,实现继承。子类型的原型对象依然存在,子类型原型中重写父类型fly方法,不会影响父类型的原型对象。有性能问题,慎用

     2.原型链方式

    因为有可能重写或添加子类型的方法,为了保证之后创建的所有子类型都继承同一个超类型,一定要在创建新实例之前修改原型对象。

      子类型构造函数.prototype=超类型的实例;

    注意:

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

      不能向超类型的构造函数中传递参数。

      如果原型被重写,最好同时修改原型的constructor属性。

      如果超类型的属性中有引用类型值,所有实例共享一个属性,不好。

    3. 组合继承

    (1)在子类型构造函数内部用call/apply调用父类型的构造函数。

    function SubType(sColor, sName) {
        SupType.apply(this, arguments); 
        this.name = sName;
    }

    注意:arguments指SubType接收到的所有参数,SupType从0位开始按顺序读取。所以SubType构造函数的参数中前面是SupType的参数,之后才是SubType用到的参数(SubType能够用标识符识别参数的值,而SupType只能通过位序使用)。

    (2)将父类型的实例赋值给子类型的原型,继承父类共享的属性和方法。

      SubType.prototype=new SuperType();
      SubType.prototype.constructor=SubType;     //原型重写时最好同时修改

    注意:组合继承会两次调用父类构造函数,在子类实例和原型中会有重复的属性。

    4.寄生式组合继承

    通过借用构造函数来继承属性,通过原型链的混合形式来继承方法。不必为了指定子类型的原型而调用超类型的构造函数,只需父类型的原型副本。

    //使用指定的原型对象创建一个新的空对象作为中间体,类似于Object.create() 方法

    //使用指定的原型对象创建一个新的空对象作为中间体,类似于Object.create() 方法
    function cloneProto(o){
        function F(){}
        F.prototype = o;
        return new F();
    }
    
    //子类型的原型为上述空对象
    function inheritPrototype(subType, superType){
        var prototype = cloneProto(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);
    };
  • 相关阅读:
    HBase with MapReduce (MultiTable Read)
    HBase with MapReduce (SummaryToFile)
    HBase with MapReduce (Summary)
    HBase with MapReduce (Read and Write)
    HBase with MapReduce (Only Read)
    Hbase中的BloomFilter(布隆过滤器)
    HBase的快照技术
    How To Use Hbase Bulk Loading
    Cloudera-Manager修改集群的IP
    Java中的HashSet和TreeSet
  • 原文地址:https://www.cnblogs.com/kevin2chen/p/7080310.html
Copyright © 2011-2022 走看看