You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
在上述例子中:name属性是只读的,即该属性的值不可修改,如果尝试为它指定新值,在非严格模式下,赋值操作会被忽略;在严格模式下,赋值操作将会导致错误:TypeError: Cannot assign to read only property 'name' of object '#<Object>'。
functionPerson(){}varfriend=newPerson();// 调用构造函数创建实例,并向实例中添加一个指向最初原型的[[Prototype]]指针,而把原型重写修改后就等于切断了构造函数与最初原型之间的联系。Person.prototype={//这里重写原型对象切断了现有的原型与任何之前已经存在的对象实例之间的联系,之前的实例引用的仍然是最初的原型constructor: Person,name : "Nicholas",age : 29,job : "Software Engineer",sayName : function(){console.log(this.name);}};friend.sayName();// TypeError: friend.sayName is not a functionvarperson=newPerson();person.sayName();// Nicholas
1. 理解对象
创建自定义对象的最简单方式就是创建一个
Object
的实例,然后再为这个实例添加相应的属性和方法,例子如下:对象字面量形式创建对象(首选方式):
2. 属性类型
2.1 数据属性
delete
删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。直接在对象上定义的属性,这个特性默认值为true;for-in
循环返回属性;直接在对象上定义的属性,这个特性默认值为true;undefined
。configurable注意点
2.2 访问器属性
访问器属性不包含数据值;它们包含一对儿
getter和setter
函数(不是必需的)。在读取访问器属性是,会调用getter函数,这个函数负责返回有效的值;在写入访问器属性时,会调用setter函数并传入新值,这个函数负责决定如何处理数据。访问器属性有如下4个特性:delete
删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为数据属性。直接在对象上定义的属性,这个特性的默认值为true
。for-in
循环返回属性。直接在对象上定义的属性,这个特性的默认值为true
。undefined
。undefined
。2.2 定义多个属性
ECMAScript5
定义了一个Object.defineProperties()方法
,可以通过描述符一次定义多个属性。接收两个对象参数:第一个对象是要添加和修改其属性的对象,第二个对象的属性与第一个对象中要添加或修改的属性一一对应。例如下例所示:2.3 读取属性的特性
ECMAScript5
的Object.getOwnPropertyDescriptor()
方法,可以取得给定属性的描述符。方法接受两个参数:属性所在的对象和要读取其描述符的属性名称。返回值是一个对象,如果是访问器属性,这个对象的属性有configurable、enumerable、get和set
;如果是数据对象,这个对象的属性有configurable、enumerable、writable和value
。例如:3. 创建对象
3.1 工厂模式
3.2 构造函数模式
要创建Person的新实例,必须使用new操作符。以这种方式调用构造函数实际上经历以下4个步骤:
3.2.1 构造函数问题
创建两个完成同样任务的Function实例的确没有必要;况且有this对象在,根本不用在执行代码前就把函数绑定到特定对象上面。因此,可以把函数定义转移到构造函数外部来解决这个问题。
3.3 原型模式
我们创建的每个函数都有一个
prototype(原型)
属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。按照字面意思来理解,prototype
就是通过调用构造函数而创建的那个对象实例的原型对象。使用原型对象的好处是: 可以让所有对象实例共享它所包含的属性和方法。即不必在构造函数中定义对象实例的信息,而是可以将这些信息直接添加到原型对象中,如下:3.3.1 理解原型对象
>如上图,展示了`Person`构造函数、`Person`的原型属性以及`Person`现有的两个实例之间的关系。其中,`Person.prototype`指向了原型对象,而`Person.prototype.constructor`又指回了`Person`。原型对象中除了包含`constructor`属性之外,还包括后来添加的其他属性。`Person`的每个实例——`person1和person2`都包含了一个内部属性,该属性仅仅指向了`Person.prototype`;换句话说,它们与构造函数没有直接关系。 ###### 3.3.2 isPrototypeOf():确定对象原型方法 ```js console.log(Person.prototype.isPrototypeOf(person1)); //true console.log(Person.prototype.isPrototypeOf(person2)); //true ``` >上述代码说明`person1和person2`内部都有一个指向`Person.prototype`的指针。 ###### 3.3.3 Object.getPrototypeOf():ECMAScript 5新增方法 ```js console.log(Object.getPrototypeOf(person1) == Person.prototype); //true console.log(Object.getPrototypeOf(person1).name); //"Nicholas" ``` >通过上述代码可知:`Object.getPrototypeOf()`方法可以方便地获取到一个对象的原型。 ###### 3.3.4 对象属性读取的搜索顺序 >每当代码读取某个对象的某个属性时,都会执行一次搜索,目标是具有给定名字的属性。**搜索首先从实例本身开始**。如果实例中找到了具有给定名字的属性,则返回该属性的值;如果没有找到,则继续搜索指针指向的原型对象,在原型对象中查找具有指定名字的属性。所以,当为对象实例添加一个属性时,这个属性就会屏蔽原型对象中保存的同名属性。这同时也是多个对象实例共享原型所保存的属性和方法的基本原理。
3.3.5 hasOwnProperty()
3.4 原型与in操作符
3.4.1 for-in循环
3.4.2 Object.keys()
3.4.3 Object.getOwnPropertyNames()
3.5 更简单的原型语法
在前面的例子中每添加一个属性和方法都要敲一遍
Person.prototype
。为了减少不必要的输入,从视觉上更好地封装原型的功能,更常见的做法是用一个包含所有属性和方法的对象字面量来重写整个原型对象,如下代码所示:3.6 原型的动态性
#### 3.7 原生对象的原型
原型模式的重要性不仅体现在创建自定义类型方面,就连所有原生的引用类型,都是采用这种模式创建的。所有原生引用类型(Object、Array、String,等等)都在其构造函数的原型上定义了方法。
3.8 原型对象的问题
首先,它省略了为构造函数传递初始化参数这一环节,结果所有实例在默认情况下都将取得相同的属性值。最重要的,其共享的本性对于函数非常合适,对于包含基本值的属性也说得过去,通过在实例上添加一个同名属性,可以隐藏原型中的对应属性。但对于包含引用类型值得属性来说,例如数组,就会有问题了。
4. 组合使用构造函数模式和原型模式
创建自定义类型的最常见方式,就是组合使用构造函数模式与原型模式。构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性。结果,每个实例都会有自己的一份实例属性的副本,但同时又共享着对方法的引用,最大限度地节省了内存。另外,这种混成模式还支持向构造函数传递参数;可谓是集两种模式之长。
该例中,实例属性都是在构造函数中定义,共享属性constructor和方法sayName()则是在原型中定义的。这种构造函数和原型混成的模式,是目前在ECMAScript中使用最广泛、认同度最高的一种创建自定义类型的方法。可以说,这是用来定义引用类型的一种默认模式。
5. 动态原型模式
动态原型模式把所有信息都封装在了构造函数中,而通过构造函数中初始化原型(仅在必要的情况下),又保持了同时使用构造函数和原型的优点。
6. 寄生构造函数模式
通常,在前几种模式都不适用的情况下,可以使用寄生(parasitic)构造函数模式。这种模式的基本思想是创建一个函数,该函数的作用仅仅是封装创建对象的代码,然后再返回新创建的对象;但从表面上看,这个函数又很像是典型的构造函数。
这个模式可以在特殊的情况下用来为对象创建构造函数。假设我们想创建一个具有额外方法的特殊数组。用于不能直接修改Array构造函数,可以使用这个模式。
7. 稳妥构造函数模式
道格拉斯 · 克罗克福德(Douglas Crockford)发明了JavaScrip中的稳妥对象(durable objects)这个概念。所谓稳妥对象,指的是没有公共属性,而且其方法也不引用this的对象。稳妥对象最适合在一些安全的环境中(这些环境中会禁止使用this和new),或者在防止数据被其他应用程序(如Mashup)改动时使用。稳妥构造函数遵循与寄生构造函数类似的模式,但有两点不同:一是新创建的对象的实例方法不引用this;二是不适用new操作符调用构造函数。
除了使用sayName()方法外,没有别的方式可以访问name的值。
变量friend中保存的是一个稳妥对象,而除了调用sayName()方法外,没有别的方式可以访问其数据成员。即使有其他代码会给这个对象添加方法或数据成员,但也不可能有别的方法访问到构造函数中的原始数据。稳妥构造函数模式提供的这种安全性,使得它非常适合在某些安全环境——例如,ADsafe和Caja提供的环境——下使用。
参考文档
The text was updated successfully, but these errors were encountered: