JavaScript中,对象的属性有两种:数据属性和访问器属性。javascript
数据属性包括一个数据值的位置。在这个位置能够读取和写入值。数据属性有4个特性。java
[[configurable]]
:可配置。表示可否删除属性、可否修改属性的特性、可否把属性变为访问器属性。[[enumerable]]
:可枚举。表示可否经过for-in循环进行遍历。[[writable]]
:可写。表示可否修改属性的值。[[value]]
:表示这个属性的数据值。ES5提供了Object.defineProperty()
方法,来设置属性的默认特性。该方法接收三个参数:属性所在对象、属性名字、属性描述符对象。其中,描述符对象用来设置configurable、enumerable、writable、value中的一个或多个值。数组
ES5也提供了Object.defineProperties
方法,能够定义多个属性。函数
configurable: false
,就不能再变回configurable: true
了。不然,不管是否处于严格模式,都会抛出TypeError错误。foncigurable: false
,仍然能够把writable的状态由true改成false,可是没法由false改成true。var person = {}; Object.defineProperty(person, 'name', { configurable: false, writable: false, value: 'Nicholas' }); // 测试:删除属性 delete person.name; // 因为configurable: false,删除失败 console.log(person.name); // Nicholas // 测试:修改特性 Object.defineProperty(person, 'name', { configurable: true }); // 抛出错误:TypeError: Cannot redefine property: name // 测试:修改属性的值 person.name = 'Greg'; // 因为writable: false,修改失败 console.log(person.name); // Nicholas
configurable: false
和writable: false
,就能够建立一个真正的常量属性。Object.seal()
方法,会在一个现有对象上调用Object.preventExtensions()
,并把全部属性标记为configurable: false
。Object.freeze()
方法,会在一个现有对象上调用Object.seal()
,并把全部属性标记为writable: false
。ES5提供了Object.getOwnPropertyDescriptor()
方法,来取得给定属性的描述符。该方法接收两个参数:属性所在对象、属性名字。返回值是一个对象,其属性有configurable、enumerable、writable、value。测试
还有一种区分枚举属性enumerable的方法是propertyIsEnumerable()
。该方法不检查原型链。this
// 使用Object.definedProperty设置的属性 var descriptor = Object.getOwnPropertyDescriptor(person, 'name'); console.log(descriptor.configurable); // false console.log(descriptor.enumerable); // false console.log(descriptor.writable); // false console.log(descriptor.value); // Nicholas // 直接定义在对象上的属性 var person2 = { name: "Greg" }; var descriptor2 = Object.getOwnPropertyDescriptor(person2, 'name'); console.log(descriptor2.configurable); // true console.log(descriptor2.enumerable); // true console.log(descriptor2.writable); // true console.log(descriptor2.value); // Greg // propertyIsEnumerable()方法 console.log(person.propertyIsEnumerable('name')); // false console.log(person2.propertyIsEnumerable('name')); // true
Object.keys(obj)
会返回一个数组,包含全部可枚举属性。不检查原型链。Object.getOwnPropertyNames(obj)
会返回一个数组,包含全部属性,不管是否枚举。不检查原型链。prop in obj
会返回一个布尔值,判断对象的属性是否存在,不管是否枚举。检查原型链。obj.hasOwnProperty(prop)
会返回一个布尔值,判断对象的指定属性是否存在,不管是否枚举。不会检查原型链。for-in
循环的遍历中。var myObject = {}; Object.defineProperty(myObject, 'a', { enumerable: true, value: 2 }); Object.defineProperty(myObject, 'b', { enumerable: false, value: 3 }); // propertyIsEnumerable console.log(myObject.propertyIsEnumerable('a')); // true console.log(myObject.propertyIsEnumerable('b')); // false // Object.keys() console.log(Object.keys(myObject)); // ["a"] // Object.getOwnPropertyNames() Object.getOwnPropertyNames(myObject); // ["a", "b"] // in操做符 console.log('a' in myObject); // true console.log('b' in myObject); // true console.log('toString' in myObject); // true // hasOwnProperty() console.log(myObject.hasOwnProperty('a')); // true console.log(myObject.hasOwnProperty('b')); // true console.log(myObject.hasOwnProperty('toString')); // false // 遍历 for (var k in myObject) { console.log( k, myObject[k] ); } // a 2
访问器属性有4个特性。对于访问器属性,JavaScript会忽略它们的writable和value特性,取而代之的该关心get和set属性。设计
[[configurable]]
:表示可否删除属性、可否修改属性的特性、可否把属性变为访问器属性。[[enumerable]]
:表示可否经过for-in循环进行遍历。直接定义在对象上的属性,默认值为true。[[get]]
:读取属性时调用的函数。直接定义在对象上的属性,默认值为undefined。[[set]]
:写入属性时调用的函数。直接定义在对象上的属性,默认值为undefined。一样使用Object.defineProperty()
方法和Object.defineProperties
方法设置访问其属性。code
var book = { _year: 2004, edition: 1 }; Object.defineProperty(book, 'year', { get: function() { return this._year; }, set: function(newYear) { if (newYear > 2004) { this._year = newYear; this.edition += (newYear - 2004); } } }); // 测试 book.year = 2005; // 注意:defineProperty中定义的属性名为year,而非_year console.log(book.edition); // 2
另外一种设置getter和setter函数的方法以下:对象
var myObject = { // 定义getter get foo() { return 'You get: ' + this._foo_; }, // 定义setter set foo(val) { this._foo_ = val; } } // 测试 myObject.foo = 2; console.log(myObject.foo); // You get: 2
一样使用Object.getOwnPropertyDescriptor()
方法取得给定属性的描述符。ip
// 使用Object.definedProperty设置的属性 var descriptor = Object.getOwnPropertyDescriptor(book, 'year'); console.log(descriptor.configurable); // false console.log(descriptor.enumerable); // false console.log(typeof descriptor.get); // function console.log(typeof descriptor.set); // function // 直接定义在对象上的属性 var descriptor = Object.getOwnPropertyDescriptor(myObject, 'foo'); console.log(descriptor.configurable); // true console.log(descriptor.enumerable); // true console.log(typeof descriptor.get); // function console.log(typeof descriptor.set); // function
参考:《JavaScript高级程序设计》、《你不知道的JavaScript(上卷)》