## 6.1 理解对象
**创建对象**
(1)创建自定义对象的最简单方式就是创建一个Object的实例,然后给其添加属性和方法:
~~~
var person = new Object();
person.name = 'tg';
person.age = 10;
person.say = function(){
console.log(this.name);
}
~~~
上面的例子创建了一个名为person的对象,并为它添加了两个属性(name、age)和一个方法(say())。
(2)对象字面量
~~~
var person = {
name: 'tg',
age: 10,
say: function(){
console.log(this.name);
}
}
~~~
这个person对象和上面例子是等价的。
### 6.1.1 属性类型
ECMA-262第5版在定义只有**内部才用的特性**(attribute)时,描述了**属性**(property)的各种特征。ECMA-262定义这些特性是为了实现JavaScript引擎用的,因此在JavaScript中**不能直接访问**它们。
ECMAScript中有两种属性:**数据属性**和**访问权属性**
**1. 数据属性**
数据属性包含一个数据值的位置,在这个位置可以读取和写入值。
数据属性有4个描述特性的属性:
| 属性 | 描述 |
|---|---|
| [[Configurable]] | 表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。比如直接在对象上定义的属性,它们的这个特性默认值为true。|
| [[Enumerable]] | 表示能否通过for-in循环返回属性。对于直接在对象上定义的值,默认为true。|
| [[Writable]] | 表示能否修改属性的值,默认为true。|
| [[Value]] | 包含这个属性的数据值。读取属性值时,从这个位置读;写入属性值时,把新值保存在这个位置。默认值为undefined。|
要修改属性默认的特性,必须使用ECMAScript 5的`Object.defineProperty()`方法,这个方法接收三个参数:属性所在的对象、属性的名字和一个描述符对象。其中,描述符对象的属性必须是:`configurable、enumerable、writable和value`中的一个或多个。
~~~
var person = {};
Object.defineProperty(person, 'name', {
writable: false,
value: 'tg'
});
console.log(person.name); // "tg"
person.name = 'tg2';
console.log(person.name); // "tg"
~~~
在上面的例子中,我们将person对象中的名为name的属性的writable设置为false,也就是不可修改,所以即使后面执行了person.name='tg2',最后person对象的name值依旧是原始值。
注意:在严格模式下,如果对一个不可修改的属性执行赋值操作,会抛出错误;非严格模式下则忽略赋值操作。
一旦将configurable特性设置为false后,就不能再把它变回可配置的了,如果再修改除writable之外的特性,都会导致错误。类似规则也适用于configurable。
在调用Obejct.defineProperty()方法时,如果不指定,configurable、writable、enumerable特性的**默认值都为false**。
**2. 访问器属性**
访问器属性不包含数据值,它们包含一对getter和setter函数(非必需)。在读取访问器属性时,会调用getter函数,返回有效的值;在写入访问器属性时,会调用setter函数并传入新值,它负责决定如何处理数据。
访问器属性:
| 属性 | 描述 |
|---|---|
| [[Configurable]] | 表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。比如直接在对象上定义的属性,它们的这个特性默认值为true。 |
| [[Enumerable]] | 表示能否通过for-in循环返回属性。对于直接在对象上定义的值,默认为true。 |
| [[Get]] | 在读取属性时调用的函数,默认为undefined |
| [[Set]] | 在写入属性时调用的函数,默认为undefined |
访问器属性不能直接定义,也是要使用Object.defineProperty()方法来定义。
~~~
var book = {
_year:2004,
edition:1
};
Object.defineProperty(book,’year’,{
get:function(){
return this._year;
},
set:function(newValue){
if (newValue>2004) {
this._year = newValue;
this.edition += newValue-2004;
}
}
});
book.year = 2005;
alert(book.edition); //2
~~~
以上代码创建了一个book对象,并给它定义了两个默认属性:`_year和edition`。前面的下划线是一种常用的记号,用于表示**只能通过对象方法访问的属性**。在这个函数里,把year属性修改为2005会导致`_year`变成2005,而`edition`变为2。这是使用访问器属性的常见方式,即**设置一个属性的值会导致其他属性发生变化。**
**3. 定义多个属性**
ECMAScript 5提供的Object.defineProperties()方法可以通过描述符一次定义多个属性,这个方法接收两个对象参数,第一个对象是要添加和修改其属性的对象,第二个对象的属性与第一个对象要添加或修改的属性一一对应。
~~~
var book = {};
Object.defineProperties(book,{
_year: {
value:2004
},
edition:{
value:1
},
year:{
get:function(){
return this._year;
},
set:function(newValue){
if (newValue>2004) {
this._year = newValue;
this.edition += newValue-2004;
}
}
}
});
~~~
**4. 读取属性的特性**
ECMAScript 5提供的`Object.getOwnPropertyDescriptor()`方法可以取得给定属性的描述符,它接受两个参数:属性所在的对象和要读取其描述符的属性名称,返回来的是一个对象,如果是访问器属性,这个对象的属性有configurable、enumerable、get和set;如果是数据属性,这个对象的属性有configurable、enumerable、writable和value。
~~~
var descriptor = Object.getOwnpropertyDescriptor(book,’_year’);
alert(descriptor.value) //2005
alert(descriptor.configurable) //false
alert(descriptor.get) //undefined
console.log(descriptor.enumerable); // false
console.log(typeof descriptor.get); // "function"
~~~
这个方法只能用于实例属性,要取得原型属性的描述符,必须直接在原型对象上调用这个方法。
在JavaScript中,可以针对任何对象--包括DOM和BOM对象,使用Object.getOwnPropertyDescriptor()方法。
- 前言
- 第一章 JavaScript简介
- 第三章 基本概念
- 3.1-3.3 语法、关键字和变量
- 3.4 数据类型
- 3.5-3.6 操作符、流控制语句(暂略)
- 3.7函数
- 第四章 变量的值、作用域与内存问题
- 第五章 引用类型
- 5.1 Object类型
- 5.2 Array类型
- 5.3 Date类型
- 5.4 基本包装类型
- 5.5 单体内置对象
- 第六章 面向对象的程序设计
- 6.1 理解对象
- 6.2 创建对象
- 6.3 继承
- 第七章 函数
- 7.1 函数概述
- 7.2 闭包
- 7.3 私有变量
- 第八章 BOM
- 8.1 window对象
- 8.2 location对象
- 8.3 navigator、screen与history对象
- 第九章 DOM
- 9.1 节点层次
- 9.2 DOM操作技术
- 9.3 DOM扩展
- 9.4 DOM2和DOM3
- 第十章 事件
- 10.1 事件流
- 10.2 事件处理程序
- 10.3 事件对象
- 10.4 事件类型
- 第十一章 JSON
- 11.1-11.2 语法与序列化选项
- 第十二章 正则表达式
- 12.1 创建正则表达式
- 12.2-12.3 模式匹配与RegExp对象
- 第十三章 Ajax
- 13.1 XMLHttpRequest对象
- 你不知道的JavaScript
- 一、作用域与闭包
- 1.1 作用域
- 1.2 词法作用域
- 1.3 函数作用域与块作用域
- 1.4 提升
- 1.5 作用域闭包
- 二、this与对象原型
- 2.1 关于this
- 2.2 全面解析this
- 2.3 对象
- 2.4 混合对象“类”
- 2.5 原型
- 2.6 行为委托
- 三、类型与语法
- 3.1 类型
- 3.2 值
- 3.3 原生函数