首页 未命名正文

linux编程_JavaScript之继续(原型链)

云返利网 未命名 2020-05-26 09:05:59 18 0

我们知道继续是oo语言中不能缺少的一部门,对于JavaScript也是云云。一样平常的继续有两种方式:其一,接口继续,只继续方式的署名;其二,实现继续,继续现实的方式。JavaScript不支持署名,因此只有实现继续。其中实现继续主要是依赖于原型链的。下面我将以原型链为重点说说继续的几种主要的方式:

原型链继续
借用组织函数继续
组合继续(重点)
第一部门:原型链继续

  A

  要说原型链继续,不得不首先先容一下原型链的观点。

  想象一下,若是使原型工具即是另一个工具的实例,则此时原型工具将包罗一个指向另一个原型的指针。响应地,另一个原型也将包罗指向另一个组织函数的指针。假设另一个原型又是另一个类型的实例,那么上述关系依然建立,云云层层递进,就构成了实例与原型的链条(注重:这里的实例和原型都是相对的),这便是原型链的基本观点。

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

  在上述代码中,我们可以看出subType的原型是SuperType的实例,因此,原来存在于SuperType的实例中的所有属性和方式,现在也存在于SubType.prototype中了。且我们没有使用SubType默认提供的原型工具,而是给它换了一个新原型工具(即SuperType的实例)。因此,新原型工具不仅具有作为一个SuperType的实例所拥有的所有属性和方式,而且其内部另有一个指针,指向了SuperType的原型。即:instance指向SubType的原型,SubType的原型指向了SuperType的原型。值得注重的是:property现在位于SubType.protoType中(由于SuperType组织函数中的this指向的是建立的工具实例)。

  当以读取模式接见一个实例属性时,搜索历程会沿着原型链向上举行搜索。好比,挪用instance.getSuperValue()会履历三个搜索步骤:(1).搜索实例中是否存在该方式,效果:无。(2).沿着原型链向上,搜索SubType.prototype中是否存在该方式,效果:无。(3).继续沿着原型链,搜索SuperType.prototype中是否存在该方式,效果:存在。于是住手搜索。也就是说:在找不到属性或方式的情况下,搜索历程总是要一环一环地前行到原型链末尾才会停下来。

   注重:instance.constructor现在指向的是SuperType,这是由于SubType的原型指向了另一个工具--SuperType的原型,而这个原型工具的constructor属性指向的是SuperType。我们可以用以下代码做出验证:

console.log(instance.constructor);

  最终返回的是SuperType这个组织函数。

  主要:别忘记默认的原型。我们知道,所有的引用类型都继续了Object,而这个继续也是通过原型链实现的,即所有函数的默认原型都是Object的实例,因此默认原型都市包罗一个内部指针,指向Object.prototype。这也是所有引用类型都市继续toString()、valueOf()方式的根本原因。我们可以使用下面代码做出验证:

console.log(Object.prototype.isPrototypeOf(instance));//true
console.log(SuperType.prototype.isPrototypeOf(instance));//true
console.log(SubType.prototype.isPrototypeOf(instance));//true

  也就是说instace实例工具的原型工具分别是Object.prototype、SuperType.prototype、SubType.prototype。另外我们还可以使用instanceof操作符判断,实例instance与组织函数之间的关系,如下所示:

console.log(instance instanceof Object);//true
console.log(instance instanceof SuperType);//true
console.log(instance instanceof SubType);//true

  即instance是Object SuperType SubType的实例。下面我们使用一张图表示意他们之间的关系。

  这里,我们可以以为加粗的线条就是原型链(实例与原型的链条)。

  从这张图表中,我们可以看到SubType Prototype是没有constructer属性的,更没有指向SubType组织函数,这是由于建立SubType组织函数同时建立的原型工具和这个原型工具不是同一个,这个原型工具是SuperType的实例。注重到,后两个原型工具都有一个[[prototype]]属性,由于这时他们是被看成实例来处置的。

  B

  郑重地界说方式

  当子类型有时候需要笼罩(与原型中笼罩属性是同样的原理,见《深入明白JavaScript中建立工具模式的演变(原型)》)超类型的某个方式,或者需要添加超类型中不存在的某个方式。这时,应当注重:给原型添加方式的代码一定要放在(用超类型的工具实例作为子类型的原型来)替换原型的语句之后。看以下代码:

    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;//这时在子类型中新添加的方式
}
SubType.prototype.getSuperValue=function(){
    return false;//这时在子类型添加的超类型的同名方式,用于笼罩超类型中的方式,因此,最后忏悔了false
}
var instance= new SubType();
console.log(instance.getSuperValue());//false

  若是顺序颠倒,那么这两个新添加的方式就是无效的了,最终instance.getSuperValue()获得的效果仍然是从超类型中搜索到的,返回false。这时由于若是颠倒,那么后面添加的方式给了SubType最最先的原型,后面替换原型之后,就只能继续超类型的,而刚刚添加的方式不会被实例所共享,此时实例的[[prototype]]指向的是替换之后的原型工具而不在指向最初的添加了方式的原型工具。

  另有一点需要注重的就是,在通过原型链实现继续时,不能使用工具字面量建立原型方式(这样就会再次建立一个原型工具,而不会刚刚的谁人用超类型的实例替换的工具),由于这样会切断原型链,无法实现继续。

  C

  单独使用原型链的问题

 问题1: 最主要的问题是当包罗引用类型值的原型。首先,回首以下原型模式建立工具的方式,对于包罗引用类型值的原型属性会被所有的实例共享,这样改变其中一个实例,其他都市被改变,这不是我们想要的。这也正是之前关于原型的解说中为什么要将引用类型的值界说在组织函数中而不是界说在原型工具中。对于原型链,也是同样的问题。

  看以下的代码;

    function SuperType(){
  this.colors=["red","blue","green"];
}
function SubType(){}
SubType.prototype=new SuperType();//这时,SuperType中的this工具指向的是SubType.prototype
var instance1=new SubType();
instance1.colors.push("black");
console.log(instance1.colors);//["red", "blue", "green", "black"]
var instance2=new SubType();
console.log(instance2.colors);//["red", "blue", "green", "black"]

  在SuperType组织函数中的this一定是指向由他建立的新工具的,而SubType.prototype正是这个新工具,因此SubType的原型工具便有了colors属性,由于这个属性值是数组(引用类型),因而只管我们的本意是向instance1中添加一个“black”,但最终不能制止的影响到了instance2。而colors放在组织函数中有问题,若是放在其他的原型工具中,依然会有问题。因此,这是原型链继续的一个问题。

  问题二:

  在建立子类型的实例时,不能向超类型的组织函数通报参数。现实上,应该说没有办法在不影响所有工具实例的情况下,给超类型的组织函数通报参数。

  正由于单单使用原型链来实现继续泛起的以上两个问题,我们在实践中很少会单独使用原型链。

第二部门:借用组织函数继续
  A

  为解决以上问题,人们发明晰借用组织函数(又称伪造工具或经典继续),这种方式的焦点头脑是:在子类型组织函数的内部挪用超类型组织函数。由于函数只不过是在特定环境中执行代码的工具,因此通过使用apply()和call()方式也可以在(未来)新建立的工具上执行组织函数。注重:这种继续方式没有用到原型链的知识,与基于原型链的继续毫无关系。代码如下:

function SuperType(){
    this.colors=["red","blue","green"];
}
function SubType(){
    SuperType.call(this);//在子类型组织函数的内部挪用超类型组织函数
}
var instance1=new SubType();
instance1.colors.push("black");
console.log(instance1.colors);//["red", "blue", "green", "black"]
var instance2=new SubType();
console.log(instance2.colors);//["red", "blue", "green"]

  首先,我们可以看到此种继续方式既完成了继续义务,又到达了我们希望到达的效果:对一个实例的值为引用类型的属性的修改不影响另一个实例的引用类型的属性值。

  值得注重的是:这种继续方式与原型链的继续方式是完全差别的。看以下代码:

console.log(instance1 instanceof SubType);//true
console.log(instance1 instanceof SuperType);//false

  instance1和instance2都不是SuperType的实例。这里的继续只是表面上的继续。我们可以剖析一下这个继续的历程:首先声明晰两个组织函数,然后执行var instance1=new SubType();即通过new挪用了组织函数SubType,既然挪用了SubType组织函数,此时便进入了SubType执行环境,该环境中又挪用了SuperType()函数(注重:这里未使用new,故此时应当把SuperType函数看成一样平常函数来处置),又由于SubType()中this是指向instance1(SubType是组织函数啊!)的,以是,接下来就会在instance1工具上挪用通俗函数SuperType,由于这个通俗函数在instance1上被挪用,因此,SuperType中的this又指向了Instance1,这是,instance1工具便添加了属性值为应用类型的colors属性,instance2同理。

  这解决了原型链继续中的第一个问题。

  B

  相对于原型链而言,借用组织函数有一个很大的优势,即可以在子类型组织函数中向超类型组织函数通报参数。如下所示:

function SuperType(name){
    this.name=name;
}
function SubType(){
    SuperType.call(this,"zzw");
    this.age=21;
}
var instance1=new SubType();
console.log(instance1.name);//zzw
console.log(instance1.age);//21

  其中SuperType.call(this,"zzw");又可以写做SuperType.apply(this,["zzw"]);(关于这一部门知识点可以看《JavaScript函数之美~ http://www.linuxidc.com/Linux/2016-11/136882.htm》第三部门)。

  言归正传,让我们先剖析函数时若何执行的:首先声明晰两个组织函数,然后通过new操作符挪用了Subtype组织函数,随即进入Subtype组织函数的执行环境,执行语句SuperType.call(this.zzw);,随即进入了通俗函数(同样地,只要没有使用new操作符,它就是一样平常函数)的执行环境并通报了参数,且使用了call方式,说明在instance1工具上挪用通俗函数SuperType,由于在工具上挪用的,以是SuperType函数中的this指向instance1,并最终获得了name属性。SuperType函数执行环境中的代码执行完毕之后,执行环境又回到了SubType组织函数,这时,instance工具又获得了属性值为21的age属性。

  ok!借用组织函数继续又解决了原型链继续的第二个问题。

  然而,借用组织函数就没有瑕玷吗?谜底是有!由于仅仅使用借用组织函数,就无法制止组织函数模式的问题--方式在组织函数中界说(而导致虚耗)。而且,我们说这种方式与原型链差别,因此在超类型的原型中界说的方式,对子类型而言也是不能见的,效果所有类型都只能使用组织函数模式。

  考虑到上述问题,借用组织函数的手艺也是很少单独使用的。

第三部门:组合继续(伪经典继续)
  与建立工具时,我们将自界说组织函数模式和原型模式组合一样,这种继续方式即将原型链和借用组织函数的手艺组合到一起,从而施展两者之长。主要头脑是:使用原型链实现对原型属性(即希望让各个实例共享的属性)和方式(对于借用组织函数,继续方式显然是不合适的)的继续,而通过借用组织函数来实现对实例属性(即不希望共享的属性,之前方式是通过实例属性笼罩原型属性)的继续。这样,既通过在原型上界说方式实现了函数复用(即只建立一次方式,被多次使用,若是将函数界说在组织函数中,建立一个实例,就会同时建立一个相同的方式,无法复用,影响性能),又能够保证每个实例都有自己的属性(由于借用组织函数可以通报参数啊!把实例属性通过借用组织函数实现,就不用去笼罩了)。

下面来看这样一个例子:

function SuperType(name,age){
    this.name=name;//实例属性使用借用组织函数模式               this.age=age;//实例属性使用借用组织函数模式
    this.colors=["red","blue","green"];//这个数组虽然会同时被原型链和借用组织函数添加使用,但最后凭据原型链的搜索机制,是根据借用组织函数模式实现的。
}
SuperType.prototype.sayName=function(){
    console.log(this.name);//实现同样效果的方式使用原型链模式
};
function SubType(name,age){
    SuperType.call(this,name,age);//借用组织函数模式的有点就是可以向子类型组织函数中的超类型组织函数通报参数,这里this的用法很主要
   
};
SubType.prototype=new SuperType();//使用SuperType的实例来替换为SubType的原型工具
SubType.prototype.constructor=SubType;// 这句代码即将SubType的原型工具的constructor属性指向SubType,但这一句去掉也不会影响效果。
SubType.prototype.sayAge=function(){
    console.log(this.age);//在原型工具中界说方式,可以使得该方式实现复用,增强性能
};
var instance1=new SubType("zzw",21);
instance1.colors.push("black");
console.log(instance1.colors);//["red", "blue", "green", "black"]
instance1.sayName();//zzw
instance1.sayAge();//21
var instance2=new SubType("ht",18);
console.log(instance2.colors);//["red", "blue", "green"]
instance2.sayName();//ht
instance2.sayAge();//18

【关于云返利网】

云返利网是阿里云、腾讯云、华为云产品推广返利平台,在各个品牌云产品官网优惠活动之外,云返利网还提供返利。您可以无门槛获得阿里云、华为云、腾讯云所有产品返利,在官网下单后就可以领取,无论是自己用、公司用还是帮客户采购,您个人都可以获得返利。云返利网的目标是让返利更多、更快、更简单!详情咨询13121395187(微信同号)