第六章 面向对象的程序设计app
1. 数据属性函数
[[Configurable]]:表示可否经过delete删除属性从而从新定义属性。默认值为true。测试
[[Enumerable]]:表示可否经过for-in循环返回属性。默认值为true。this
[[Writable]]:表示可否修改属性的值,默认为true。spa
[[Value]]:包含这个属性的数据值。默认为undefined。prototype
要修改属性默认的特性,必须使用ECMAScript5的Object.defineProperty( )方法。接收三个参数:属性所在对象,属性名字和一个描述符对象。其中,描述符对象的属性必须是:configurable、enumerable、writable和value。设计
能够屡次调用Object.defineProperty()方法需改同一属性,但在把configurable特性设置为false以后就会有限制了。指针
2. 访问器属性对象
访问器属性不包含数据值,包含一对getter和setter函数。继承
[[Configurable]]:表示可否经过delete删除属性从而从新定义属性。默认值为true。
[[Enumerable]]:表示可否经过for-in循环返回属性。默认值为true。
[[Get]]:在读取属性时调用的函数,默认值为undefined。
[[Set]]:在写入属性时调用的函数,默认值为undefined。
定义多个属性,ECMAScript5定义了Object.defineProperties()方法。
3. 使用ECMAScript5的Object.getOwnPropertyDescriptor()方法,能够取得给定属性的描述符。此方法接收两个参数:属性所在的对象和要读取其描述符的属性名称。返回值是一个对象。
4. 建立对象
方法 |
细节 |
工厂模式 |
用函数来封装以特定接口建立对象的细节。 |
优势:能够无数次调用函数。 |
|
缺点:但没有解决对象识别的问题。 |
|
构造函数模式 |
没有显示地建立对象; 直接将属性和方法赋给了this对象; 没有return语句。 构造函数始终都以一个大写字母开头,而非构造函数应该以一个小写字母开头。 要建立构造函数的新实例,必须使用new操做符。 |
优势:构造函数模式赛过工厂模式的地方在于:能够将它的实例标识为一种特定的类型。 |
|
缺点:每一个方法都要在每一个实例上从新建立一遍。 |
|
原型模式 |
每一个函数都有一个prototype(原型)属性,此属性是一个指针,指向一个对象,此对象的用途是包含能够由特定类型的全部实例共享的属性和方法。 当为对象实例添加一个属性时,这个属性就会屏蔽原型对象中保存的同名属性,但不会修改那个属性。使用delete操做符则能够彻底删除实例属性,可以从新访问原型中的属性。 hasOwnProperty( )方法能够检测一个属性是存在于实例中,仍是存在于原型中。只有存在于对象实例中,才会返回true。 单独使用时,in操做符会在经过对象可以访问给定属性时返回true,不管该属性存在于实例中仍是原型中。只要in操做符返回true,而hasOwnProperty( )返回false,就能够肯定属性时原型中的属性。 hasPrototypeProperty( )方法,当原型属性存在时,返回true,当原型属性被实例重写时,返回false。 在使用for-in循环时,返回的是全部可以经过对象访问的、可枚举的属性,其中既包括存在于实例中的属性,也包括存在于原型中的属性。 重写原型对象切断了现有原型与任何以前已经存在的对象实例之间的联系,他们引用的仍然是最初的原型。 |
优势:可让全部对象实例共享它所包含的属性和方法,即没必要再构造函数中定义对象实例的信息,而是能够将这些信息直接添加到原型对象中。 |
|
缺点:由共享本质,对于包含引用类型值的属性而言问题突出。 |
|
组合使用构造函数模式和原型模式 |
建立自定义的最多见方式,也是用来定义引用类型的默认形式。 实例属性在构造函数中定义,全部实例共享的属性constructor和方法都在原型中定义。 |
优势:集构造函数与原型模式之所长。 |
|
动态原型模式 |
使用if语句检查初始化以后应该存在的任何属性或方法。采用该模式建立的对象能够用instanceof操做符肯定它的类型。 |
寄生构造函数模式 |
除了使用new操做符并把使用的包装函数叫作构造函数以外,此模式与工厂模式是同样的。构造函数在不返回值的状况下,默认会返回新对象实例,而经过在构造函数的末尾添加一个return语句,能够重写调用构造函数返回的值。 返回的对象与构造函数或者构造函数的原型属性直接没有关系。 不能依赖instanceof操做符来肯定对象类型。 可使用其余模式,尽可能不要使用该模式 |
稳妥构造函数模式 |
稳妥对象:没有公共属性,并且其方法也不引用this的对象。 与寄生构造模式的两点不一样:一是新建立对象的实例方法不引用this;二是不使用new操做符调用构造函数。 |
5. OO语言通常支持两种继承方式:接口集成和实现继承。接口集成只继承方法签名,而实现继承则集继承实际的方法。ECMAScript只支持实现继承,且主要依赖原型链来实现。
6. 原型链的基本思想是利用原型让一个引用类型继承另外一个引用类型的属性和方法。每一个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。
functionSuperType(){
this.property = true;
}
SuperType.prototype.getSuperValue= function( ){
returnthis.property;
}
functionSubType(){
this.subproperty = false;
}
SubType.prototype= new SuperType();
SubType.prototype.getSubValue= function(){
return this.subproperty;
}
instance.getSubValue() //false
instance.getSuperValue() //true
7. 全部引用类型默认都集成了Object,而这个继承也是经过原型链实现的。
8. 肯定原型和实例的两种方法:一是使用instanceof操做符,用这个操做符来测试实例与原型链中出现过的构造函数,结果就会返回true,第二种方式是使用isPrototypeOf( )方法,只要原型链中出现过的原型,均可以说是该原型链所派生的实例的原型。
9. 给原型添加方法的代码必定要放在替换原型的语句以后,另外,在经过原型链实现继承时,不能使用对象字面量建立原型方法。
10. 继承
方法 |
实现 |
原型链 |
利用原型让一个引用类型继承另外一个引用类型的属性和方法。每一个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。 |
原型链的两大问题,一是来自包含引用类型值的原型,另外一个是在建立子类型的实例时,不能向超类型的构造函数中传递参数。 |
|
借用构造函数 |
使用apply()和call( )方法在新建立的对象上执行构造函数。 |
优势:相对于原型链而言,能够在子类型构造函数中向超类型构造函数传递参数 |
|
缺点:方法都在构造函数中定义,所以函数复用就无从谈起。 |
|
组合集成 |
将原型链和借用构造函数的技术一块儿,取长处的方式。原理是使用原型链实现对原型属性和方法的集成,而经过借用构造函数来实现对实例属性的继承。 |
优势:避免了原型链和借用构造函数的缺陷,融合了它们的优势,成为JavaScript中最经常使用的继承模式。并且,instanceof和isPrototypeOf( )也可以用于识别基于组合继承建立的对象。 |
|
缺点:不管什么状况下,都会调用两次超类型构造函数,一次是在建立子类型原型的时候,另外一次是在子类型构造函数内部。 |
|
原型式继承 |
此方法没有严格意义上的构造函数,借助原型能够基于已有的对象建立新对象,同时还没必要所以建立自定义类型。 ECMAScript经过新增Object.create( )方法规范化了原型式继承。 |
缺点:包含引用类型值的属性始终都会共享相应的值,就像使用原型模式同样。 |
|
寄生式继承 |
建立一个仅用于封装继承过程的函数,该函数在内部以某种方式来加强对象,最后再像真的处理以后同样返回对象。 |
缺点:使用寄生式集成来为对象添加函数,会因为不能作到函数复用而下降效率 |
|
寄生组合式继承 |
经过借用构造函数来继承属性,经过原型链的混成形式来继承方法。基本思路是:没必要为了指定子类型的原型而调用超烈性的构造函数,咱们所须要的是超类型原型的一个副本而已。即便用寄生式继承来继承超类型的原型,而后再将结果指定给子类型的原型。 |
优势:效率高,值调用一次超类型原型的构造函数,原型链还能保持不变,能正常使用instanceof和isPrototypeOf( )。是最理想的继承范式。 |