简介

JavaScript 是一门基于对象的编程语言,在 JavaScript 中一切都是对象,包括函数,也是被当成第一等的对象对待,这正是 JavaScript 极其富有表现力的原因。


理解对象

ECMA-262 关于对象的定义是:“无序属性的集合,其属性可以包含基本值、对象或者函数。” 严格说,对象是一组没有特定顺序的值。对象的每个属性或方法都有一个名字,而每个名字都映射到一个值。

  1. 早期,创建对象就是创建一个 Object的实例,并为它添加属性( name、age )和方法( sayName() ),可以这么写:

    1
    2
    3
    4
    5
    6
    var person = new Object();
    person.name = "Davis";
    person.age = 22;
    person.sayName = function () {
    alert(this.name);
    }
  2. 现在,对象字面量成为创建对象的首选模式,可以这么写:

    1
    2
    3
    4
    5
    6
    7
    8
    var person = {
    name = "Davis",
    age: 22,
    sayName: function () {
    alert(this.name);
    }
    };

这两个例子中 person 对象事一样的,有相同的属性和方法。这些属性在创建时都有一些特征值(characteristic),JavaScript 通过这些特征值来定义他们的行为。

属性类型

ECMAScript 中有两种属性:数据属性和访问器属性。

  • 数据属性
    数据属性包含一个数据值的位置,在这个位置可以读取和写入值,具有如下4个特性:

[[Configurable]]: 表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,能否把属
性修改为访问器属性。直接在对象上定义的属性,默认为 true。
[[Enumerable]]: 表示能否通过for-in循环返回属性。直接在对象上定义的属性,默认为true。
[[Writable]]: 表示能否修改属性的值。直接在对象上定义的属性,默认为true。
[[Value]]: 包含这个属性的数据值;读取属性值的时候,从这个位置读取;写入属性值的时候,把值保存在这里。这个特性默认为undefined

要修改数据属性默认的特性,必须使用ECMAScript5中的Object.defineProperty()方法;接受三个参数:属性所在的对象、属性的名字、描述符对象;其中,数据属性描述符对象的属性必须是:configurable、enumerable、writable和value。

1
2
3
4
5
6
7
8
var person = {};
Object.defineProperty(person, "name", {
writable: false,
value: "Davis"
});
alert(person.name); //"Davis"
person.name = "XX";
alert(person.name); //"Davis"

  • 访问器属性
    访问器属性包含一对 getter 和 setter 函数。在读取访问器属性时,会调用 getter 函数,负责返回有效的值;在写入时,会调用 setter 函数并传入新值,负责决定如何处理数据。具有如下4个特性:

[[Configurable]]: 表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,能否把属
性修改为访问器属性。直接在对象上定义的属性,默认为 true。
[[Enumerable]]: 表示能否通过for-in循环返回属性。直接在对象上定义的属性,默认为true。
[[Get]]: 在读取属性时调用的函数;默认值为undefined。在读取访问器属性时,会调用gette方法,这个函数负责返回有效的值。
[[Set]]: 在写入属性时调用的函数;默认值为undefined。在写入访问器属性时,会调用setter方法并传入新值,这个函数负责决定如何处理数据。

访问器属性不能直接定义,必须使用Object.defineProperty()方法来定义。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var book = {
_year: 2016,
edition: 5
};
Object.defineProperty(book, "year", {
get: function () {
return this._year;
},
set: function (newVal) {
if (newVal > 2016) {
this._year = newVal;
this.edition += newVal - 2016;
}
}
});
book.year = 2017;
alert(book.edition); // 6

定义多个属性

Object.defineProperties()方法,通过描述符一次性定义多个属性;

接收两个对象参数:第一个对象是要添加或修改其属性的对象;第二个对象的属性与第一个对象中要添加或修改的属性一一对应。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var book = {};
Object.defineProperties(book, {
_year: {
writable: true,
value: 2016
},
edition: {
writable: true,
value: 5
},
year: {
get: function () {
return this._year;
},
set: function (newVal) {
if (newVal > 2016) {
this._year = newVal;
this.edition += newVal - 2016;
}
}
}
});

以上代码在 book 对象上定义了两个数据属性( _year 和 edition )和一个访问器属性
( year )。

读取属性的特性

Object.getOwnPropertyDescriptor()方法,可以取得给定属性的描述符;

接收两个参数:属性所在的对象,要读取其描述符的属性名称。

返回值是一个对象;如果是数据属性,这个对象的属性有configurable、enumerable、writable、value;如果是访问器属性,这个对象的属性有configurable、enumerable、get、set。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
var book = {};
Object.defineProperties(book, {
_year: {
value: 2016
},
edition: {
value: 5
},
year: {
get: function () {
return this._year;
},
set: function (newVal) {
if (newVal > 2016) {
this._year = newVal;
this.edition += newVal - 2016;
}
}
}
});
var d = Object.getOwnPropertyDescriptor(book, "_year");
alert(d.value); // 2016
alert(d.configurable); // false
alert(type d.get); // "undefined"
var d = Object.getOwnPropertyDescriptor(book, "year");
alert(d.value); // undefined
alert(d.enumerable); // false
alert(type d.get); // "function"

对于数据属性_year, value 等于最初的值,configurable 是false,而 get 等于 undefined。 对于访问属性 year,value 等于 undefined,enumerable 是 false,而 get 是指向 getter函数的指针。