ECMAScript 中有两种属性:数据属性和访问器属性。
1. 数据属性
数据属性包含一个数据值的位置。在这个位置可以读取和写入值。数据属性有4 个描述其行为的特性。
[[Configurable]]:表示能否通过delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。像前面例子中那样直接在对象上定义的属性,它们的这个特性默认值为true。
[[Enumerable]]:表示能否通过for-in 循环返回属性。像前面例子中那样直接在对象上定义的属性,它们的这个特性默认值为true。
[[Writable]]:表示能否修改属性的值。像前面例子中那样直接在对象上定义的属性,它们的这个特性默认值为true。
[[Value]]:包含这个属性的数据值。读取属性值的时候,从这个位置读;写入属性值的时候,把新值保存在这个位置。这个特性的默认值为 undefined。
可以多次调用Object.defineProperty()方法修改同一个属性,但在把configurable特性设置为false 之后就会有限制了。
在调用Object.defineProperty()方法时,如果不指定,configurable、enumerable 和writable 特性的默认值都是false。
2. 访问器属性
访问器属性不包含数据值;它们包含一对儿getter 和setter 函数(不过,这两个函数都不是必需的)。在读取访问器属性时,会调用getter 函数,这个函数负责返回有效的值;在写入访问器属性时,会调用setter 函数并传入新值,这个函数负责决定如何处理数据。访问器属性有如下4 个特性。
[[Configurable]]:表示能否通过delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为数据属性。对于直接在对象上定义的属性,这个特性的默认值为true。
[[Enumerable]]:表示能否通过for-in 循环返回属性。对于直接在对象上定义的属性,这个特性的默认值为true。
[[Get]]:在读取属性时调用的函数。默认值为undefined。
[[Set]]:在写入属性时调用的函数。默认值为undefined。
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
以上都是摘自js高级程序设计书上第六章的讲解,最开始看的时候觉得奇奇怪怪的,不太懂这些看起来很底层的方法有什么用。
现在明白了,一个对象book,有个属性year,但是如果让用户随便一个book.year=-1;这样的话可不好啊,于是乎,book定义的year前面加了个_,表示是私有的,对于用户来说也不会知道有这么个变量,用户只会知道year,Object.defineProperty里面定义了“year”这个属性,也就是说,如果用户book.year,那么一般会返回对应的值,这里就会调用get函数,返回去的是_year值,用户来看就是book.year返回了2004,实际上内部用了get函数返回的是_year值;如果用户book.year=2017;那么实际上调用了set函数,将_year改成2017,这样用户再调用book.year就是2017了。
为什么非得加个get和set函数呢?
因为,这样增加了判断,如果set值为-1这样不是正常年份的值,那么就可以报错或者其他的,不让用户设置成功。
同时也避免了用户不小心设置错了值的情况。。