Skip to content

JS-数据描述符和访问器描述符

[!MDN]

*为什么需要设计访问器属性?访问器属性的作用似乎完全可以通过方法去代替?

1. 数据描述符

1.1 概述

  • `data
  • 主要包括以下 4 个属性: configurableenumerablewritablevalue
  • 其中,configurableenumerable 属性是 数据描述符访问器描述符 共有的公共属性。
  • 可以通过 Object.getOwnPropertyDescriptor 静态方法观察
js
if (1) {
  const obj = Object.defineProperties(
    {},
    {
      someProperty1: {
        value: 10,
        writable: true,
        enumerable: true,
        configurable: false
      }
    }
  )

  console.log(obj, Object.getOwnPropertyDescriptors(obj))
}

1.2 writable 属性

[!MDN] > writable: 如果与属性相关联的值可以使用赋值运算符更改,则为 true。默认值为 false

  • 这个属性是 数据描述符 特有的,这一点很好理解,只有数据才有 writable 的意义。

1.3 value 属性

  • 就是数据属性的具体数值
  • 也是 数据描述符 特有的属性

2. 访问器描述符

  • `accessor
  • gettersetter
  • 具体代码如下
js
if (1) {
  const obj2 = {
    name: 'Alice',
    age: 55
  }

  Object.defineProperty(obj2, 'phone', {
    value: 42
    // enumerable: true
  })

  Object.defineProperty(obj2, 'age', {
    get: function () {
      console.log('get it')
      return 55
    },

    set: function (newVal) {
      console.log('set it', newVal)
    }
  })

  // console.log(Object.getOwnPropertyDescriptors(obj2))
  console.log(obj2)
  // console.log(obj2.age)
  // obj2.age = 888
}

  • 再次修改 getset 都会出错,因为二者的属性是一个函数
js
const obj = {}

Object.defineProperty(obj, 'name', {
  value: 'yancey',
  configurable: false
})

// Uncaught TypeError: Cannot redefine property: name
Object.defineProperty(obj, 'name', { get: function () {} })

// Uncaught TypeError: Cannot redefine property: name
Object.defineProperty(obj, 'name', { set: function () {} })

3. 数据描述符和 访问器描述符的公共属性

  • configurable 属性:

[!MDN] > configurable 当设置为 false 时,

  • 该属性的类型 不能在数据属性和访问器属性之间更改,且
  • 该属性不可被删除,且
  • 其描述符的其他属性也不能被更改(但是,如果它是一个可写的数据描述符,则 value 可以被更改,writable 可以更改为 false)。
js
// configurable and writable
if (1) {
  const obj3 = { name: 'Eric' }
  Object.defineProperty(obj3, 'age', {
    value: 20,
    writable: true,
    enumerable: true,
    configurable: false
  })

  // if configurable: false but writable: true
  // you can still change the value
  obj3.age = 800
  console.log(obj3)

  /******************************************/
  // defineProperty can change the existing property, not redefine it
  //console.log(Object.getOwnPropertyDescriptor(obj3, 'age'))

  // if configurable is false, you can still change 'writable' from 'true' to 'false'
  // but can not from 'false' to 'true'
  Object.defineProperty(obj3, 'age', {
    value: 8,
    writable: false,
    configurable: false
  })
  console.log(obj3)

  // error: can not change writable from 'false' to 'true', if 'configurable' is 'false'
  /*
  Object.defineProperty(obj3, 'age', {
    value: 100,
    writable: true
  })
  */
}
  • 如果 configurablefalse ,那么 writable 只能从 true 变成 false ,换言之,configurablefalse 的情况下,只允许变得更加严格,不允许变得宽松

  • enumerable 属性
    • 如果 enumerable 属性设置为 false,那么该属性在 for...of 等迭代就会被忽略,注意,console.log 的输出本质上也是一种迭代,因此,如果某个属性的 configurable 属性被设置为 false,那么 console 也不会将其输出。