首页 > 代码库 > 6面向对象的程序设计
6面向对象的程序设计
ECMA_262把对象定义为:无序属性的集合,其属性可以包含基本值、对象或者函数。
6.1理解对象
特性(attribute)是内部值,描述了属性(property)的各种特性。ECMAScript中有两种属性:数据属性和访问器属性。数据属性包含一个数据值的位置,在这个位置可以读取和写入值,数据属性有4个描述其行为的特性,[[Configurable]],[[Enumerable]],[[Writable]],[[Value]].要改变属性默认的特性,必须使用ECMAScript5的Object.defineProperty()方法,这个方法接收3个参数:属性所在的对象、属性的名字和一个描述符对象,一旦把属性定义为不可配置的,就不能再把它变回可配置了。访问器属性不包含数据值,它们包含一对getter和setter函数,访问器属性有4个特性:[[Configurable]],[[Enumerable]],[[Get]],[[Set]].
Object.defineProperties()方法可以一次定义多个属性。
Object.getOwnProperyDescriptor()方法,可以取得给定属性的描述符,这个方法接收两个参数:属性所在的对象和要读取其描述符的属性名称。
6.2创建对象
工厂模式用函数来封装以特定接口创建对象的细节。工厂模式虽然解决了创建多个相似对象的问题,但却没有解决对象识别的问题(即怎样知道一个对象的类型)。
使用构造函数模式可以定义自定义对象类型的属性和方法。按照惯例,构造函数始终都应该以一个大写字母开头,而非构造函数则应该以一个小写字母开头。创建自定义的构造函数意味着将来可以将它的实例标识为一种特定的类型,而这正是构造函数模式胜过工厂模式的地方。构造函数与其他函数的唯一区别,就在于调用它们的方式不同,任何函数,只要通过new操作符来调用,那它就可以作为构造函数。使用构造函数的主要问题,就是每个方法都要在每个实例上重新创建一遍。
我们创建的每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含由特定类型的所有实例共享的属性和方法。使用原型对象的好处是可以让所有对象实例共享它所包含的属性和方法。与构造函数模式不同的是,新对象的这些属性和方法是由所有实例共享的。只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象,所有原型对象都会自动获得一个constructor(构造函数)属性,这个属性包含一个指向prototype属性所在函数的指针。连接存在于实例和构造函数的原型对象之间,而不是存在于实例和构造函数之间。Object.getPrototypeOf()方法返回[[Prototype]]的值。可以通过对象实例访问保存在原型中的值,但却不能通过对象实例重写原型中的值,当为对象实例添加一个属性时,这个属性就会屏蔽原型对象中保存的同名属性,使用delete操作符则可以完全删除实例属性,从而让我们能够重新访问原型中的属性。使用hasOwnProperty()方法可以检测一个属性是否存在于实例中,还是存在于原型中(在对象实例中,才会返回true)。有两种方式使用in操作符:单独使用和在for-in循环中使用。单独使用时,in操作符会通过对象能够访问给定属性是返回true,不论该属性存在于实例中还是原型中。在使用for-in循环时,返回的是所有能够通过对象访问、可枚举的(enumerated)属性,其中即包括存在于实例中的属性,也包括存在于原型中的属性。Object.keys()方法可以取得对象上所有可枚举的实例属性。Object.getOwnPropertyNames()方法可以得到所有实例属性,无论是否可枚举。用对象字面量来重写原型对象,constructor属性也就变成了新对象的constructor属性(指向Object构造函数),不再指向Person函数。重写原型对象切断了现有原型与任何之前已经存在的对象实例之间的联系。原型模式省略了为构造函数传递初始化参数这一环节,结果所有实例在默认情况下都取得相同的属性值,原型模型最大问题是由其共享的本性多导致的。
创建自定义类型的最常见方式,就是组合使用构造函数模式与原型模式,构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性。
6面向对象的程序设计