对象属性描述符

102 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第36天,点击查看活动详情

属性描述符

在ES5之前,JavaScript语言本身并没有提供任何方法可以查看对象属性的特性,比如判断属性是否可修改。

思考如下代码:

var obj = {
  a: 1
}
var obj2 = {}
obj2.b = 2
// {configurable: true,enumerable: true,value: 1,writable: true}
console.log(Object.getOwnPropertyDescriptor(obj, 'a'))
// {configurable: true,enumerable: true,value: 2,writable: true}
console.log(Object.getOwnPropertyDescriptor(obj2, 'b'))

这是我们最简单的定义对象属性的方法,默认的3个配置都是true。我们来简单看下这三个属性。

writable

表达的意思是是否可以修改属性的值。

思考如下代码:

var myObject = {}
Object.defineProperty(myObject, 'a', {
  value: 100,
  writable: false, // 不可写
  configurable: true,
  enumerable: true
})
myObject.a = 200
console.log(myObject.a) // 100

在给属性a定义属性描述符时设置可读写配置是false,再对该属性进行赋值,并没有改变这个属性值,说明不可写。

在严格模式下,会报错:

'use strict'
var myObject = {}
Object.defineProperty(myObject, 'a', {
  value: 100,
  writable: false, // 不可写
  configurable: true,
  enumerable: true
})
myObject.a = 200
console.log(myObject.a) // Uncaught TypeError: Cannot assign to read only property 'a'

报错了,因为严格模式下既然设置了属性不可写,再进行赋值,明显就违背了配置不可写原则。

configurable

如果configurable属性被设置为false,则不可通过defineProperty方法来设置属性。

var myObject = {
  a: 1
}
Object.defineProperty(myObject, 'a', {
  value: 2,
  writable: true,
  configurable: false, // 不可配置
  enumerable: true
})
myObject.a = 3
console.log(myObject.a) // 3
// Uncaught TypeError: Cannot redefine property: a at Function.defineProperty
Object.defineProperty(myObject, 'a', {
  value: 4,
  writable: true,
  configurable: true,
  enumerable: true
})
console.log(myObject.a) // 未执行到

在上一个configurable设置为false之后,在通过defineProperty方法来配置属性则会产生报错,所设置的值也无效。

enumerable

这个属性描述符的含义是对象的属性是否可以被遍历到。

思考如下代码:

var myObject = {
  a:1,
  b:2,
  c:3
}
for (let attr in myObject) {
  // a b c
  console.log(attr)
}
Object.defineProperty(myObject, 'b', {
  value: 200,
  writable: true,
  configurable: true,
  enumerable: false
})
for (let attr in myObject) {
  // a c
  console.log(attr)
}
console.log(myObject.b) // 200

第一次循环myObject对象的属性,都可以输出。然后设置属性b的enumerable描述符为false,再循环,则属性b不会被循环出来,但仍可以被访问到。