JavaScript中对象的属性类型

JavaScript中,对象的属性有两种:数据属性和访问器属性。javascript

数据属性

特性:

数据属性包括一个数据值的位置。在这个位置能够读取和写入值。数据属性有4个特性。java

  • [[configurable]]:可配置。表示可否删除属性、可否修改属性的特性、可否把属性变为访问器属性。
  • [[enumerable]]:可枚举。表示可否经过for-in循环进行遍历。
  • [[writable]]:可写。表示可否修改属性的值。
  • [[value]]:表示这个属性的数据值。
设置:

ES5提供了Object.defineProperty()方法,来设置属性的默认特性。该方法接收三个参数:属性所在对象、属性名字、属性描述符对象。其中,描述符对象用来设置configurable、enumerable、writable、value中的一个或多个值。数组

ES5也提供了Object.defineProperties方法,能够定义多个属性。函数

  • 在设置了属性的特性后,任未尝试超过configurable或writable权限的操做,在非严格模式下将会被忽略,在严格模式下将会抛出错误。
  • 一旦把属性定义为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: falsewritable: false,就能够建立一个真正的常量属性。
  • Object.seal()方法,会在一个现有对象上调用Object.preventExtensions(),并把全部属性标记为configurable: false
  • Object.freeze()方法,会在一个现有对象上调用Object.seal(),并把全部属性标记为writable: false
读取:

ES5提供了Object.getOwnPropertyDescriptor()方法,来取得给定属性的描述符。该方法接收两个参数:属性所在对象、属性名字。返回值是一个对象,其属性有configurable、enumerable、writable、value。测试

还有一种区分枚举属性enumerable的方法是propertyIsEnumerable()。该方法不检查原型链。this

  • 在调用Object.defineProperty()方法时,若是不指定,configurable、enumerable、writable的默认值为false。
  • 对于直接定义在对象上的属性,configurable、enumerable、writable的默认值为true,value的值为undefined。
// 使用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

  • 不必定非要同时指定getter和setter函数。
  • 只指定getter函数意味着属性不能写。尝试写入属性,在非严格模式下将会被忽略,在严格模式下将会抛出错误。
  • 只指定setter函数意味着属性不能读。尝试读取属性,在非严格模式下将会返回undefined,在严格模式下将会抛出错误。
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.defineProperty()方法时,若是不指定,configurable、enumerable的默认值为false,get、set的默认值为undefined。
  • 对于直接定义在对象上的属性,configurable、enumerable的默认值为true。
// 使用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(上卷)》

相关文章
相关标签/搜索