基本二:javascript面向对象、建立对象、原型和继续总结(下)

媒介:此次对上篇收个尾,重要总结一下javascript的继续。

1.原型链

js中原型链是完成继续的重要要领。基本头脑是:应用原型让一个援用范例继续另一个援用范例的属性和要领。我们来简朴回想一下之前的内容:

  1. 每一个组织函数都有一个原型对象

  2. 每一个原型对象都包括一个指向组织函数的指针:(constructor)

  3. 而实例和组织函数都有一个prototype属性指针指向原型对象。

  4. 假如如今我们让原型对象(A)即是另一个范例的实例(b),此时相当于这个原型对象(A)团体作为一个实例指向另一个实例的原型对象(b的原型对象B)

  5. 以上就完成了继续。

看下面代码实例:

    function SuperType(){
        this.property = true;    //property是SuperType的实例属性
    };
    
    SuperType.prototype.getSuperValue = function(){  //getSuperValue是SuperType的原型要领
        return this.property;
    };
    
    function SubType(){
        this.subproperty = false;
    }
    
    //让SuperType继续SubType
    SubType.prototype = new SuperType();
    
    SubType.prototype.getSubValue = function(){
        return this.subproperty;
    };
    
    var instance = new SubType();
    alert(instance.getSuperValue());      //true
  1. 在上面的代码中,定义了两个范例:SuperType和SubType。每一个范例离别有一个属性和要领。

  2. 经由历程建立SuperType的实例,并赋值给了SubType.prototype,从而完成SubType继续了这个的实例,

  3. 本来存在于SuperType的实例中的一切的属性和要领,如今也存在于SubType.prototype中了。

  4. 既然如今SubType的原型对象SubType.prototype是SuperType的实例化对象,那末SuperType的实例属性property就位于SubType.prototype。以下图:

  5. 如今instance.constructor如今指向的是SuperType,图中能够看出来。也能够在举行继续以后,再举行以下步骤:
    SubType.prototype.constructor = Subtype;

《基本二:javascript面向对象、建立对象、原型和继续总结(下)》

2.完全原型链

一切函数的默许原型都是Object的实例,所以下图是上面例子的完全原型链。
《基本二:javascript面向对象、建立对象、原型和继续总结(下)》

3.重写或增加要领到超范例

(1)重写和增加要领必需在用超范例的实例(new SuperType())替代原型(SubType.prototype)以后。

    function SuperType(){
        this.property = true;    
    };
    
    SuperType.prototype.getSuperValue = function(){  
        return this.property;
    };
    
    function SubType(){
        this.subproperty = false;
    }
    
    //让SuperType继续SubType
    SubType.prototype = new SuperType();
    //增加新要领
    SubType.prototype.getSubValue = function(){
        return this.subproperty;
    };
    //重写超范例中的要领
    SubType.prototype.getSuperValue = function(){
        return false;
    };

    var instance = new SubType();
    alert(instance.getSuperValue());      //false
    alert((new SuperType()).getSuperValue());   //我模仿java这么写,竟然返回true
  1. 重写超范例中的要领以后,经由历程SuperType的实例挪用getSuperValue()时,挪用的就是这个从新定义的要领。

  2. 经由历程SuperType的实例挪用getSuperValue()时,挪用的就是超范例中的要领,返回true

(2)经由历程原型链完成继续时,不能运用对象字面量建立原型要领,如许会重写原型链

    function SuperType(){
        this.property = true;    
    };
    
    SuperType.prototype.getSuperValue = function(){  
        return this.property;
    };
    
    function SubType(){
        this.subproperty = false;
    }
    
    //让SuperType继续SubType
    SubType.prototype = new SuperType();
    
    SubType.prototype = {
        getSubValue: function(){
            return this.subproperty;
        },
        someOtherMethod: function(){
            return false;
        }
    };

    var instance = new SubType();
    alert(instance.getSuperValue());      //error

(3)原型链的题目

  1. 在经由历程原型链举行继续时,原型现实上会变成另一个范例的实例,所以本来的实例属性也就变成了如今的原型属性了。

  2. 如今假如原型实例的属性是援用范例的,那末它会直接被增加成如今的对象原型的属性,那末经由历程这个建立的实例对这个援用范例的属性举行更改时,会马上反应在一切的实例对象上。

看下面代码:

    function SuperType(){
        this.colors = ["red","blue","green"];    
    };
    
    function SubType(){
    }
    
    //让SubType继续SuperType
    SubType.prototype = new SuperType();
    
    var instance1 = new SubType();
    instance1.colors.push("black");
    alert(instance1.colors);       //["red","blue","green","black"]
    
    var instance2 = new SubType();
    alert(instance2.colors);        //["red","blue","green","black"]
  1. 当SubType经由历程原型链继续了SuperType以后,SubType.prototype就变成了SuperType的一个实例

  2. 此时SubType具有一个本身的colors属性就像特地建立了一个SubType.prototype.colors属性一样

  3. 此时SubType一切的实例话对象都邑同享这个colors属性,修正instances1的colors属性会马上在instances2中显示出来。

原型链另有一个题目:在建立子范例的实例时,不能向超范例的组织函数通报参数,现实上是没有办法在不影响一切对象实例的情况下,给超范例的组织函数通报参数。

4.完成继续的别的要领

(1)借用组织函数

基本头脑:

  1. 在子范例组织函数的内部挪用超范例的组织函数,经由历程运用call()要领或许apply()要领。

例子:

    function SuperType(name){
        this.name = name;
        this.colors = ["red","blue","green"];
    }
    
    function SubType(name,age){
        //继续了SuperType,同时还通报了参数
        SuperType.call(this,name);
        //再为子范例定义属性
        this.age = age;
    }
    
    var instance1 = new SubType("Jack");
    alert(instance1.name);
    instance1.colors.push("black");
    alert(instance1.colors);       //"red,blue,green,black"
    
    var instance2 = new SubType();
    alert(instance2.colors);        //"red,blue,green"
  1. 上述代码中处理了一个题目,就是援用范例的属性题目,每一个实例化的子范例都有本身的特有的属性

  2. 还存在一个题目,假如要领都定义在组织函数中,那末要领的就不能复用。

(2)组合继续-最经常使用的继续形式

组合继续的思绪是:

  1. 运用原型链完成对原型属性和要领的继续,经由历程借用组织函数来完成对实例属性的继续

  2. 如许既经由历程在原型上定义要领完成了函数复用,又能够保证每一个实例都有它本身的属性。

例子:

    function SuperType(name){
        this.name = name;
        this.colors = ["red","blue","green"];
    }
    SuperType.prototype.sayName = function(){
        alert(this.name);
    };
    
    function SubType(name,age){
        //继续SuperType的属性
        SuperType.call(this,name);
        this.age = age;
    }
    
    //继续SuperType的要领
    SubType.prototype = new SuperType();
    //定义子范例本身的要领
    SubType.prototype.sayAge = function(){
        alert(this.age);
    };
    
    var instance1 = new SubType("Jack",26);
    instance1.colors.push("black");
    alert(instance1.colors);       //"red,blue,green,black"
    instance1.sayName();          //Jack
    instance1.sayAge();          //26
    
    var instance2 = new SubType("Rose",23);
    alert(instance2.colors);      //"red,blue,green"
    instance2.sayName();          //Rose
    instance2.sayAge();           //23

(3)原型式继续

思绪:借助原型能够基于已有的对象建立新对象,还没必要因而建立本身的自定义范例
以下:

    function object(o){
        function F(){};
        F.prototype = o;
        return new F();
    }
  1. object()函数内部先建立一个暂时性的函数。

  2. 然后将传入的对象作为这个组织函数的原型。

  3. 末了返回这个暂时范例的饿新实例。

以下:

    var person = {
        name:"Jack",
        friends:["路人甲","路人乙"]
    };
    var anotherPerson = object(person);   //此处挪用上方的object要领
    anotherPerson.name = "Rose";
    anotherPerson.friends.push("路人丙");
    
    var yetPerson = object(person);
    yetPerson.name = "Rick";
    yetPerson.friends.push("路人丁");
    
    alert(person.friends);      //["路人甲","路人乙","路人丙","路人丁"]

上述person.friends不仅属于person一切,而且会被anotherPerson和yetPerson同享。
另有Object.create()要领,前面已总结过了。

(4)寄生式继续

思绪:建立一个仅用于封装继续历程的函数。

    function createAnother(original){
        var clone = object(original);    //挪用前面的object()要领
        clone.sayHi = function(){
            alert("hi");
        };
        return clone;
    }
    
    //运用
    var person = {
        name:"Jack",
        friends:["路人甲","路人乙","路人丙"]
    };
    var anotherPerson = createAnother(person);
    anotherPerson.sayHi();       //"Hi"
    

5.寄生组合式继续

(1)组合继续存在的题目

组合继续是js最经常使用的继续形式,不过它有本身的不足,组合继续最大的题目在于要挪用两次超范例的组织函数一次是建立超范例的实例赋值给子范例的原型对象时一次是子范例组织函数内部
终究子范例会包括超范例对象的悉数实例属性,然则我们不得不在挪用子范例组织函数时重写这些属性。

看下面例子:

    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;
    }
    
    SubType.prototype = new SuperType();        //第一次挪用
    SubType.prototype.constructor = SubType;
    SubType.prototype.sayAge = function(){
        alert(this.age);
    };
  1. 第一次挪用SuperType组织函数时,SubType.prototype会获得两个属性:name和colors,它们都是SuperType的实例属性,只不过位于SubType的原型中。

  2. 当挪用SubType的组织函数时,在函数内部又会挪用SuperType的组织函数,又在新对象上建立了实例属性name和colors,因而这两个属性就屏障了原型中的同名属性。

(2)处理要领

寄生组合式继续的头脑是:没必要为了子范例的原型而挪用超范例的组织函数,我们所须要的不过就是超范例的一个副本罢了,本质上就是运用寄生式继续来继续超范例的原型,把返回的效果赋值给子范例的原型。

人人肯定还记得上面说的原型式继续吧吧,将一个对象浅赋值给另一个对象,如今也能够把一个超范例的原型赋值给另一个子范例原型

1.回想一下object()函数的代码

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

2.建立一个函数,它吸收两个参数:子范例组织函数和超范例组织函数。

    function inheritPrototype(subType,superType){
        var prototype = object(superType.prototype);
        prototype.constructor = subType;
        subType.prototype = prototype;
    }
  1. 上面的代码第一步建立超范例原型的一个副本

  2. 为建立的副本增加constructor属性,填补因重写原型而落空默许的constructor属性
    此处的重写发生在object()函数内里,超范例的原型superType.prototype直接赋给了F.prototype,然后object()函数又返回了F的新实例。

  3. 把建立新的对象赋值给子范例的原型

3.那末如今来运用一下

    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);
    };
    
  1. 上述代码高效率,由于它只挪用了一次SuperType的组织函数,因而避免了在SubType.prototype上面建立没必要要的、过剩的属性,

  2. 此时原型链还能坚持稳定。

以上~~~~~

    原文作者:yangdepp
    原文地址: https://segmentfault.com/a/1190000005946069
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞