建立对象的几种体式格局
在逻辑上从初级到高等:工场形式、组织函数形式、原型形式、组合形式。固然另有其他形式,然则这四者逻辑关系强,总结起来很有以为。之所以和继续一同剖析,也是由于逻辑关系很清楚:原型形式对应原型链继续,组织函数形式对应借用组织函数形式继续,组合形式对应组合继续。逻辑上根据“哪一个形式有什么瑕玷,为何有这个瑕玷,我们怎样处理这个瑕玷”逐渐剖析,如许剖析完后就会恍然大悟。
1)工场形式
运用函数建立对象,该函数来封装建立对象的细节。
function createObject(para1,para2,para3){
var o = new Object();//显式建立对象
o.colors = [para1, para2, para3];
o.sayColors = function() {
console.log(this.colors[0]);
}
return o;//返回对象
}
var ob1 = createObject("red", "green", "blue");
console.log(ob1);
console.log(ob1.colors);
ob1.sayColors();
console.log(ob1 instanceof createObject);//false,没法推断对象的范例
瑕玷:没法推断对象范例。
2)组织函数形式
经由过程组织函数建立的实例被标识为一种特定的范例,能够经由过程instanceof 推断对象范例。
function createObject(para1, para2, para3) {
//经由过程this完成函数属性定义,不必显现建立对象,因而也不必返回对象
this.colors = [
para1,
para2,
para3
];
this.sayColors = function () {
console.log(this.colors[0]);
}
}
var ob1 = new createObject('red', 'green', 'blue');
console.log(ob1);
console.log(ob1.colors);
ob1.sayColors();
console.log(ob1 instanceof createObject); //true,能够推断对象的范例
瑕玷:经由过程组织函数建立的实例具有差别的要领和属性,属性能够差别,这对实例来说是好的,我们愿望实例属性自力。然则要领即函数,函数即对象,也就是说建立了太多反复的对象。
var ob1 = new createObject("red", "green", "blue");
var ob2 = new createObject("red", "green", "blue");
alert(ob1.sayColors == ob2.sayColors);//false,差别实例具有差别的要领
处理体式格局:把要领的定义放到组织函数外部,即在组织函数内部援用外部全局函数。如许就能够一次定义,屡次援用。然则当外部全局函数增多时,显著降低了封装性,《JavaScript精炼》上提到,全局对象是EScript的一大败笔。
<script type="text/javascript">
function createObject(para1,para2,para3){
//经由过程this完成函数属性定义,不必显现建立对象,因而也不必返回对象
this.colors = [para1, para2, para3];
this.sayColors=sayColors;
}
function sayColors(){
alert(this.colors[0]);
}
var ob1 = new createObject("red", "green", "blue");
var ob2 = new createObject("red", "green", "blue");
alert(ob1.sayColors == ob2.sayColors);//true
alert(ob1.colors == ob2.colors);//false ,在组织函数中建立的援用范例属性是差别的
</script>
值得一提的是,组织函数建立的实例中的援用范例属性是很特别的,这一点会随后提到。
3) 原型形式
:每个函数都有一个prototype属性,这个属性指向经由过程组织函数建立的实例对象的原型对象。原型对象的要领和属性能够被它的一切实例同享。因而,经由过程把属性和要领添加到实例的原型对象上,能够完成属性和要领同享。
<script type="text/javascript">
function createObject(){
}
createObject.prototype.colors = ["red", "green", "blue"];
createObject.prototype.sayColors = function(){
alert(this.colors[0]);
}
var ob1 = new createObject();
var ob2 = new createObject();
alert(ob1.sayColors == ob2.sayColors);//true,经由过程原型建立的属性和要领同享
alert(ob1.colors == ob2.colors);//true
</script>
瑕玷:“成也萧何,败也萧何”,原型形式的瑕玷就在于过强的同享才能,要领的同享能够削减过剩的对象实例建立。然则属性同享致使实例难以具有本身奇特属性。固然,假如是一些不会修正的属性值,同享也就罢了;然则假如是须要修正的属性,而且该属性值是援用范例(基础范例属性值能够在实例中定义,会覆蓋掉原型属性,然则不会修正原型属性,其他的实例接见该属性照旧对应原型属性),那末实例对这个属性值的修正就会在原型中反应出来,这实在就是修正了原型。蹩脚的是其他实例中的该属性也同步变化,然后就会涌现新鲜的题目。
<script type="text/javascript">
function createObject(){
}
createObject.prototype.colors = ["red", "green", "blue"];
createObject.prototype.sayColors = function(){
alert(this.colors[0]);
}
var ob1 = new createObject();
var ob2 = new createObject();
ob1.colors.push("yellow");
alert(ob1.colors);//red,green,blue,yellow
alert(ob2.colors);//red,green,blue,yellow,经由过程ob1做的改变在ob2反应出来
</script>
4) 组合形式(最经常使用的一种对象建立体式格局,统筹长处,防止瑕玷)
:运用组织函数形式定义各个实例属性,运用原型形式定义要领和同享的属性。
<script type="text/javascript">
function createObject(){
this.colors = ["red", "green", "blue"];
}
createObject.prototype.sayColors = function(){
alert(this.colors[0]);
}
var ob1 = new createObject();
var ob2 = new createObject();
alert(ob1.sayColors == ob2.sayColors);//true,经由过程原型建立的要领同享
alert(ob1.colors == ob2.colors);//flase,组织函数建立的援用范例属性不同享
</script>
补充关于对象的几个要领:
isPrototypeOf(): 肯定一个对象是不是是另一个对象的原型,只假如原型链中涌现的原型,就返回true,运用要领:
alert(createObject.prototype.isPrototypeOf(ob1));//rue
instanceof操作符:检测是不是是某一组织函数的实例,前面的参数是实例, 背面的的参数是组织函数名,只假如原型链中涌现的组织函数就返回true。
alert(ob1 instanceof createObject);//true
hasOwnProperty(): 检测一个实例是不是具有某个属性,运用要领
alert(ob1.hasOwnProperty("colors"));//true
in操作符:零丁运用时能够搜检实例属性或许原型属性是不是存在,in后跟的平常是实例,因而能够理解为搜检实例以及实例对应的原型中是不是有这个属性或不法。运用要领:
alert("sayColors" in ob1);//true
alert("sayColors" in createObject);//false,直接对原型搜检没意义
for in 的另一种用法,类似于数组的forEach()要领,是一个轮回,返回实例或原型中的可罗列的属性。
<script type="text/javascript">
function createObject(){
this.colors = ["red", "green", "blue"];
}
createObject.prototype.sayColors = function(){
alert(this.colors[0]);
}
var ob1 = new createObject();
for (var prop in ob1) {
alert(prop); //前后弹出colors sayColors
}
</script>
继续的完成:
1.原型链
:把超范例的实例复制给子范例的原型,如许超范例的要领和属性就由子范例继续。
<script type="text/javascript">
//组合形式定义超范例对象
function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperValue = function(){
return this.property;
};
function SubType(){
this.subproperty = false;
}
//经由过程建立超范例对象实例而且赋值给子范例原型完成继续
SubType.prototype = new SuperType();
var instance = new SubType();
//true,子范例接见超范例的要领,完成了继续
alert(instance.getSuperValue());
</script>
题目:子范例原型会继续超范例实例的属性,假如这个属性值是援用范例,就会致使子范例的一切实例都同享了这个属性,致使差别实例属性的耦合,这是原型形式建立对象的固有题目。而且,在建立子范例的实例时,没法向超范例的组织函数通报参数。因而,现实中很少零丁运用原型链。
2 借用组织函数(典范继续)
在子范例组织函数的内部挪用超范例组织函数。这个要领之所以被称为借用组织函数,我以为就是由于这类要领和前面引见的经由过程组织函数建立实例的私有属性是一样的原理,只不过是在子范例组织函数内部挪用了超范例组织函数。
<script type="text/javascript">
function SuperType(){
this.colors = ["red", "blue", "green"];
}
//借用组织函数,在子范例组织函数的内部挪用超范例组织函数
function SubType(){
SuperType.call(this);
}
//每次挪用发生的实例具有差别的援用范例属性
var instance1 = new SubType();
alert(instance1.colors);//red,blue,green
instance1.colors.push("yellow");
alert(instance1.colors);//red,blue,green,yellow
var instance2 = new SubType();
alert(instance2.colors);//red,blue,green,从原型继续的实例属性是私有的
alert(ob1.colors == ob2.colors);//false,属性私有
alert(ob1.sayColors == ob2.sayColors);//false,要领也是私有
</script>
而且能够在建立子范例实例时向超范例通报参数,由于这就相当于挪用了一个函数,函数固然是能够有参数的。
瑕玷是一样具有组织函数形式建立对象的固有弊病:组织函数中烦人要领(函数对象)反复建立。而且,只要在超范例组织函数中定义的属性和要领才会被继续,经由过程超范例原型定义的要领和属性对子范例不可见,这是由于只执行了组织函数内部的语句。因而现实中这个要领也很少零丁运用。
<script type="text/javascript">
function SuperType(){
this.colors = ["red", "blue", "green"];
}
//超范例的原型上建立要领
SuperType.prototype.sayColors = function(){
alert(this.colors[0]);
return 0;
}
//借用组织函数,在子范例组织函数的内部挪用超范例组织函数
function SubType(){
SuperType.call(this);
}
var ob1 = new SubType();
var ob2 = new SuperType();
alert(ob1.sayColors);//undefined,子范例不具有这个要领
ob2.sayColors();//red,超范例具有这个要领
</script>
3 组合继续(伪典范形式继续)
将原型链继续和借用组织函数形式组合到一同,运用原型链完成对原型属性和要领的继续(完成了要领复用),然则经由过程借用组织函数完成对实例属性的继续(完成了实例属性私有)。防止了缺点,融会了长处,是最经常使用的继续形式,而且,instanceof操作符和isPrototypeOf()都适用于组合继续建立的对象。
<script type="text/javascript">
function SuperType(){
this.colors = ["red", "blue", "green"];
}
//超范例的原型上建立要领
SuperType.prototype.sayColors = function(){
alert(this.colors[0]);
return 0;
}
//借用组织函数,在子范例组织函数的内部挪用超范例组织函数,完成属性继续
function SubType(){
SuperType.call(this);
}
//原型链完成要领继续
SubType.prototype = new SuperType();
var ob1 = new SubType();
ob1.sayColors();//red//子范例继续了超范例原型的要领
</script>