属性类型
JS中有两种属性:数据属性和访问器属性。
数据属性
数据属性包含一个数据值的位置;在这个位置可以读取和写入值。
数据属性具有4个描述其行为的特性:
[[Configurable]]
表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,能否把属性修改为访问器属性。
直接在对象上定义的属性,默认为true。
[[Enumerable]]
表示能否通过for-in循环返回属性。
直接在对象上定义的属性,默认为true。
除了for-in循环之外,ECMAScript5定义了两个用以枚举属性名称的函数。
Object.keys():返回一个数组,这个数组由对象中可枚举的自有属性的名称组成。
其工作原理类似这样:
1 function keys(object) { 2 if(typeof object !== "object") { 3 throw TypeError; //参数必须是对象 4 }; 5 var result = []; //创建一个数组,用以保存枚举的属性 6 for (prop in object) { //遍历所有可枚举的属性 7 if (object.hasOwnProperty(prop)) { //判断是否为自有属性 8 result.push(prop); //将属性名添加到数组 9 }; 10 }; 11 return result; //返回数组 12 };
Object.getOwnPropertyNames():返回对象的所有自有属性的名称,而不仅限于可枚举的属性。
[[Writable]]
表示能否修改属性的值。
直接在对象上定义的属性,默认为true。
[[Value]]
包含这个属性的数据值;读取属性值的时候,从这个位置读取;写入属性值的时候,把值保存在这里。
这个特性默认为undefined。
访问器属性
访问器属性包含一对getter和setter方法。
如果属性同时具有getter和setter方法,那么它就是一个读/写属性;如果只有getter方法,则为只读属性;同理,如果只有setter方法,则为只写属性。
访问器属性有如下4个特性:
[[Configurable]]
表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,能否把属性修改为数据属性。
直接在对象上定义的属性,默认为true。
[[Enumerable]]
表示能否通过for-in循环返回属性。
直接在对象上定义的属性,默认为true。
[[Get]]
在读取属性时调用的函数;默认值为undefined。
在读取访问器属性时,会调用gette方法,这个函数负责返回有效的值。
[[Set]]
在写入属性时调用的函数;默认值为undefined。
在写入访问器属性时,会调用setter方法并传入新值,这个函数负责决定如何处理数据。
访问器属性不能直接定义,必须使用Object.defineProperties()方法来定义。
定义多个属性
要修改数据属性默认的特性,必须使用ECMAScript5中的Object.defineProperty()方法;接受三个参数:属性所在的对象、属性的名字、描述符对象;其中,数据属性描述符对象的属性必须是:configurable、enumerable、writable、value;访问器属性的描述符对象的属性有configurable、enumerable、get、set。设置其中的一个或多个值,可以修改对应的特性值。
1 var person = {}; 2 Object.defineProperty(person, "name", { 3 writable: false, 4 value: "CC" 5 }); 6 alert(person.name); //"CC" 7 person.name = "VV"; 8 alert(person.name); //"CC"
在调用Object.defineProperty()方法新建属性时,如果不指定,configurable、enumerable、writable特性的值都是false。
注意:使用Object.defineProperty()方法,要么修改已有属性,要么新建自有属性,不能修改继承属性。
Object.defineProperties()方法,通过描述符一次性定义多个属性;
接收两个对象参数:第一个对象是要添加或修改其属性的对象;第二个对象的属性与第一个对象中要添加或修改的属性一一对应。
1 var person = {}; 2 Object.defineProperties(person, { 3 name: { 4 value: "CC", 5 writable: true 6 }, 7 age: { 8 value: 23, 9 writable: false 10 } 11 }); 12 alert(person.name); //"CC" 13 person.name = "VV"; 14 alert(person.name); //"VV"
读取属性的特性
Object.getOwnPropertyDescriptor()方法,可以取得给定属性的描述符;
接收两个参数:属性所在的对象,要读取其描述符的属性名称。
返回值是一个对象;如果是数据属性,这个对象的属性有configurable、enumerable、writable、value;如果是访问器属性,这个对象的属性有configurable、enumerable、get、set。
1 var person = {}; 2 Object.defineProperties(person, { 3 name: { 4 value: "CC", 5 writable: true 6 }, 7 age: { 8 value: 23, 9 writable: false 10 } 11 }); 12 var descriptor = Object.getOwnPropertyDescriptor(person, "name"); 13 alert(descriptor.value); //"CC" 14 alert(descriptor.writable); //true
注意:
Object.getOwnPropertyDescriptor()方法,只能用于实例属性;如果要取得原型属性的描述符,必须直接在原型对象上调用Object.getOwnPropertyDescriptor()方法。
《JS权威指南》——Object.getOwnPropertyDescriptor()方法只能取得自有属性的描述符,要想获得继承的属性,必须遍历原型链。
属性的特性规则
如果对象是不可扩展的,则可以编辑已有的自有属性,但不能添加新属性;
如果属性是不可配置的,则不能修改它的可配置性和可枚举性(一旦将confidurable特性改为false,不能再改回true);
如果访问器属性是不可配置的,则不能修改其getter和setter方法,也不能将其转换为数据类型;
如果数据属性是不可配置的,则不能将它的writable特性从false改为true,但可以从true改为false;也不能将其转换为访问器属性;
如果数据属性是不可配置且不可写的,则不能修改它的value值;然而可配置但不可写的value值是可以修改的(实际上是先标记为可写的,然后修改value值,最后转换为不可写的)。
