媒介:此次对上篇收个尾,重要总结一下javascript的继续。
1.原型链
js中原型链是完成继续的重要要领。基本头脑是:应用原型让一个援用范例继续另一个援用范例的属性和要领。我们来简朴回想一下之前的内容:
每一个组织函数都有一个原型对象
每一个原型对象都包括一个指向组织函数的指针:(constructor)
而实例和组织函数都有一个prototype属性指针指向原型对象。
假如如今我们
让原型对象(A)即是另一个范例的实例(b)
,此时相当于这个原型对象(A)团体作为一个实例指向另一个实例的原型对象(b的原型对象B)
。以上就完成了继续。
看下面代码实例:
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
在上面的代码中,定义了两个范例:SuperType和SubType。每一个范例离别有一个属性和要领。
经由历程建立SuperType的实例,并赋值给了SubType.prototype,从而完成SubType继续了这个的实例,
本来存在于SuperType的实例中的一切的属性和要领,如今也存在于SubType.prototype中了。
既然如今SubType的原型对象SubType.prototype是SuperType的实例化对象,那末
SuperType的实例属性property就位于SubType.prototype
。以下图:如今instance.constructor如今指向的是SuperType,图中能够看出来。也能够在举行继续以后,再举行以下步骤:
SubType.prototype.constructor = Subtype;
2.完全原型链
一切函数的默许原型都是Object的实例
,所以下图是上面例子的完全原型链。
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
重写超范例中的要领以后,经由历程SuperType的实例挪用
getSuperValue()
时,挪用的就是这个从新定义的要领。经由历程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)原型链的题目
在经由历程原型链举行继续时,原型现实上会变成另一个范例的实例,所以本来的实例属性也就变成了如今的原型属性了。
如今假如原型实例的属性是援用范例的,那末它会直接被增加成如今的对象原型的属性,那末经由历程这个建立的实例对这个援用范例的属性举行更改时,会马上反应在一切的实例对象上。
看下面代码:
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"]
当SubType经由历程原型链继续了SuperType以后,SubType.prototype就变成了SuperType的一个实例
此时
SubType具有一个本身的colors属性
,就像特地建立了一个SubType.prototype.colors属性一样
此时SubType一切的实例话对象都邑同享这个colors属性,修正instances1的colors属性会马上在instances2中显示出来。
原型链另有一个题目:在建立子范例的实例时,不能向超范例的组织函数通报参数,现实上是没有办法在不影响一切对象实例的情况下,给超范例的组织函数通报参数。
4.完成继续的别的要领
(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"
上述代码中处理了一个题目,就是援用范例的属性题目,每一个实例化的子范例都有本身的特有的属性
还存在一个题目,假如要领都定义在组织函数中,那末要领的就不能复用。
(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();
}
在
object()
函数内部先建立一个暂时性的函数。然后将传入的对象作为这个组织函数的原型。
末了返回这个暂时范例的饿新实例。
以下:
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);
};
第一次挪用SuperType组织函数时,SubType.prototype会获得两个属性:name和colors,它们都是SuperType的实例属性,只不过位于SubType的原型中。
当挪用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;
}
上面的代码第一步建立超范例原型的一个副本
为建立的副本增加constructor属性,填补因重写原型而落空默许的constructor属性
此处的重写发生在object()
函数内里,超范例的原型superType.prototype直接赋给了F.prototype,然后object()
函数又返回了F的新实例。把建立新的对象赋值给子范例的原型
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);
};
上述代码高效率,由于它只挪用了一次SuperType的组织函数,因而避免了在SubType.prototype上面建立没必要要的、过剩的属性,
此时原型链还能坚持稳定。
以上~~~~~