之前曾经简单总结过js中的对象,见“【第24期】浅析js中的类和对象”。
从数据结构的层面去理解,完全可以将“对象”理解为一组没有顺序的名值对。但是因为js中没有“类”的概念,传统编程语言中类有属性和方法,而且其属性方法可以通过public
、private
等修饰符进行修饰,这样不仅可以灵活的控制类属性和方法的访问,但是针对类的实例——对象而言,并没有类似的方式可以进行控制。
但是在js中,对象的属性可以通过“特性”来设置,或者来控制外界对其的访问(包括读和写)。
ECMA-262第5版在定义只有内部才用的特性(attribute)时,描述了属性(property)的各种特征。
对象的属性可以分为两类:数据属性 和 访问器属性。不同类的属性分别会有不同的描述特征。
- 数据属性
- 访问器属性
“数据属性”包含一个数据值的位置,在这个位置可以读取和写入值。是可读取和写入值的属性。
“数据属性”有4个描述其行为的特性:
- [[Configurable]]:表示能否通过
delete
删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。 - [[Enumerable]]:表示能否通过
for-in
循环返回属性。 - [[Writable]]:表示能否修改属性的值。
- [[Value]]:包含这个属性的数据值。
- 读取属性值的时候,从这个位置读;
- 写入属性值的时候,把新值保存在这个位置。
“访问器属性”不包含数据值,包含一对儿getter和setter函数(不过,这两个函数都不是必需的)。
只要设置或检索属性值,“访问器属性”就会调用用户提供的函数:
- 在读取访问器属性时,会调用getter函数,这个函数负责返回有效的值
- 在写入访问器属性时,会调用setter函数,并传入新值,这个函数负责决定如何处理数据。
“访问器属性”有如下4个特征:
- [[Configurable]]:表示能否通过
delete
删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为数据属性。 - [[Enumerable]]:表示能否通过
for-in
循环返回属性。 - [[Get]]:在读取属性时调用的函数。
- [[Set]]:在写入属性时调用的函数。
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
“数据属性”可以直接定义,但“访问器属性”不能直接定义,必须使用Object.defineProperty()
来定义(也可以定义数据属性)。
也许对“访问器属性”怎么使用很困惑,但是从上面代码可以看出,其实对属性的读/写方法并无差别,只是 内部的处理逻辑不同。
在读取和写入属性值时,会受到属性特性的影响。相关的方法有:
- Object.defineProperty():定义属性
- Object.defineProperies():定义多个属性
in
运算符- Object.prototype.hasOwnProperty()
- Object.getOwnPropertyDescriptor():读取属性的特性
- getOwnPropertyNames()
- Object.keys()
for-in
循环
- https://segmentfault.com/a/1190000006800082
- https://msdn.microsoft.com/zh-cn/library/hh965578(v=vs.94).aspx
(本篇完)