ECMA-262把对象定义为:“无序属性的集合,其属性可以包含基本值、对象或者函数。”
创建对象
-
传建一个
Object
实例,然后添加属性和方法。var person = new Object(); person.name = "Zhang San"; person.age = 20; person.sayName = function() { alert(this.name); }
上面的例子创建了一个名为 person 的对象,并为它添加了两个属性(name、age)和一个 方法(sayName())。其中,sayName()方法用于显示 this.name(将被解析为 person.name)的值。
-
对象字面量
前面的例子可以用可以写成这样:
var person = { name: "Zhang San", age: 20, sayName: function(){ alert(this.name); } }
属性类型
ECMA-262定义了一些用来描述属性各种特征的特性。这些特性是为了实现 JavaScript 引擎用的,因此不能直接访问这些特性。为了表示特性是内部值,该规范把它们放在了两对方括号中,例如:[[Enumerable]]
。
ECMAScript中有两种属性:数据属性和访问器属性。
数据属性
数据属性包含一个数据值的位置。在这个位置可以读取和写入值。数据属性有四个描述其行为的特性。
特性 | 描述 | 默认值 |
---|---|---|
Configurable | 表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。 |
true |
Enumerable | 表示能否通过 for-in 循环返回属性 | true |
Writable | 表示能否修改属性的值 | true |
Value | 包含这个属性的数据值。读取属性值的时候,从这个位置读;写入属性值的时候,把新值保存在这个位置。 | undefined |
当直接在对象上定义的属性:
var person = {
name: "Zhang San"
}
这里创建了一个名为 name 的属性,为它指定的值是"Nicholas"。也就是说,[[Value]]
特性将 被设置为"Nicholas",而对这个值的任何修改都将反映在这个位置。
要修改属性默认的特性,必须使用 ECMAScript 5 的 Object.defineProperty()
方法。这个方法接受三个参数:属性所在的对象,属性的名字以及一个描述对象。
var person = {
name: "Zhang San"
}
Object.defineProperty(person, 'name', {
writable: false,
value: 'zjl'
})
person.name = 'yyq';
console.log(person.name); // zjl
Object.defineProperty(person, 'name', {
configurable: false
})
delete person.name;
console.log(person.name); // zjl
把 configurable 设置为 false,表示不能从对象中删除属性。如果对这个属性调用 delete,则 在非严格模式下什么也不会发生,而在严格模式下会导致错误。而且,一旦把属性定义为不可配置的, 就不能再把它变回可配置了。
例如,对上面的对象在重新设置 [[writeable]
]特性将出现报错:
Object.defineProperty(person, 'name', {
writable: true
})
Object.defineProperty(person, 'name', {
^
TypeError: Cannot redefine property: name
...
访问器属性
访问器属性不包含数据值;它们包含一对 getter
和 setter
函数(不过,这两个函数都不是必需的)。
在读取访问器属性时,会调用 getter 函数,这个函数负责返回有效的值;在写入访问器属性时,会调用 setter 函数并传入新值,这个函数负责决定如何处理数据。访问器属性有如下 4 个特性。
特性 | 描述 | 默认值 |
---|---|---|
Configurable | 表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特 性,或者能否把属性修改为数据属性。 | true |
Enumerable | 表示能否通过 for-in 循环返回属性。 | true |
Get | 在读取属性时调用的函数。 | undefined |
Set | 在写入属性时调用的函数。 | undefined |
看到这里,你也许会有疑惑,那类似于上面用对象字面量定义的对象,其属性是什么属性呢?答案是:数据属性。因为,访问器属性不能直接定义,必须使用 Object.defineProperty()来定义。
var person = {
_firstName: "Zhang",
_lastName: "San"
}
Object.defineProperty(person, 'name', {
get: function() {
return this._firstName + ' ' + this._lastName;
},
set: function(lastName) {
this._lastName = lastName;
console.log('Congratulations!!!');
}
})
console.log(person.name); //Zhang San
person.name = 'Jialu'; //Congratulations!!!
console.log(person.name); //Zhang Jialu
以上代码创建了一个对象,并给它定义了两个默认的属性:_firstName
,_lastName
。前面的下划线是一种常用的记号,用于表示只能通过对象方法访问的属性。而访问器属性 year 则包含一个 getter 函数和一个 setter 函数。
不一定非要同时指定 getter 和 setter。只指定 getter 意味着属性是不能写,尝试写入属性会被忽略。 在严格模式下,尝试写入只指定了 getter 函数的属性会抛出错误。类似地,只指定 setter 函数的属性也 不能读,否则在非严格模式下会返回 undefined,而在严格模式下会抛出错误。
兼容性:
支持 ECMAScript 5 的这个方法的浏览器有 IE9+(IE8 只是部分实现)、Firefox 4+、Safari 5+、Opera 12+和 Chrome。在这个方法之前,要创建访问器属性,一般都使用两个非标准的方法: __defineGetter__()
和 __defineSetter__()
。
person.__defineGetter__("name", function() {
return this._firstName + ' ' + this._lastName;
})
person.__defineSetter__("name", function(lastName) {