Skip to content

彻底搞懂对象的数据属性描述符、存储属性描述符

属性描述符

js
  let obj = {
    name: "ziu",
    age: 18
  }
  Object.defineProperty(obj, "height", {
    value: 1.88
  })
  console.log(obj) // { name: 'ziu', age: 18 }
  let obj = {
    name: "ziu",
    age: 18
  }
  Object.defineProperty(obj, "height", {
    value: 1.88
  })
  console.log(obj) // { name: 'ziu', age: 18 }

obj对象的控制台输出中,并没有defineProperty新定义的height,这是因为不可枚举的(不可遍历的),在打印时并没有和其他属性一起输出。这个属性已经被添加到对象中,只不过不可见。

js
  console.log(obj.height) // 1.88
  console.log(obj.height) // 1.88

属性描述符是一个对象,根据功能不同,可以分为两类:数据属性描述符存储属性描述符

数据属性描述符

  • 数据属性描述符(Data Properties)
    • value该属性对应的值,默认undefined
    • configurable该属性描述符是否可被改变、是否可被删除,默认为false
    • enumerable该属性是否可被枚举,默认为false
    • writable该属性是否可以被写入新的值,默认为false

没有用属性描述符定义的对象属性(直接使用.语法),也是具有以上属性描述符的特性的,value值为属性被赋值的值,其他configurableemumerablewritable默认值都为true注意,属性描述符区全为小写。

js
  let obj = {
    name: "ziu",
    age: 18
  }
  // 数据属性描述符
  Object.defineProperty(obj, "address", {
    value: "Beijing", // 该属性对应的值,默认为undefine
    configurable: false, // 该属性描述符是否可被改变、是否可被删除,默认为false
    enumerable: true, // 该属性是否可被枚举,默认为false
    writable: true // 该属性是否可以被写入新的值,默认为false
  })
  // configurable
  delete obj.address
  obj.address = "Shanghai"
  console.log(obj.address) // Beijing
  // enumerable
  console.log(obj)
  for(let key in obj) {
    console.log(key)
  }
  console.log(Object.keys(obj))
  // writable
  obj.address = "Tianjin"
  console.log(obj.address)
  let obj = {
    name: "ziu",
    age: 18
  }
  // 数据属性描述符
  Object.defineProperty(obj, "address", {
    value: "Beijing", // 该属性对应的值,默认为undefine
    configurable: false, // 该属性描述符是否可被改变、是否可被删除,默认为false
    enumerable: true, // 该属性是否可被枚举,默认为false
    writable: true // 该属性是否可以被写入新的值,默认为false
  })
  // configurable
  delete obj.address
  obj.address = "Shanghai"
  console.log(obj.address) // Beijing
  // enumerable
  console.log(obj)
  for(let key in obj) {
    console.log(key)
  }
  console.log(Object.keys(obj))
  // writable
  obj.address = "Tianjin"
  console.log(obj.address)

存储属性描述符

  • 存储属性描述符(Accessor Properties)
    • get当访问该属性时,会调用此函数,默认为undefined
    • set当属性值被修改时,会调用此函数,默认为undefined

注意,getset描述符与vaulewritable描述符不共存。

configurableenumerablevaluewritablegetset
数据描述符可以可以可以可以不可以不可以
存取描述符可以可以不可以不可以可以可以
js
  let obj = {
    name: "ziu",
    age: 18,
    _address: "Beijing"
  }
  // Accessor Properties
  Object.defineProperty(obj, "address", {
    enumerable: true,
    configurable: true,
    // value: "Beijing",
    // writable: true,
    get: function() {
        return this._address
    },
    set: function(val) {
        this._address = val
    }
  })
  console.log(obj.address) // 调用getter() Beijing
  obj.address = "Shanghai" // 调用setter()
  console.log(obj._address) // Shanghai
  let obj = {
    name: "ziu",
    age: 18,
    _address: "Beijing"
  }
  // Accessor Properties
  Object.defineProperty(obj, "address", {
    enumerable: true,
    configurable: true,
    // value: "Beijing",
    // writable: true,
    get: function() {
        return this._address
    },
    set: function(val) {
        this._address = val
    }
  })
  console.log(obj.address) // 调用getter() Beijing
  obj.address = "Shanghai" // 调用setter()
  console.log(obj._address) // Shanghai

应用场景

  1. 隐藏某个私有属性,希望直接被外界使用和赋值。(下划线开头的变量一般为私有属性)
  2. 获取某个属性被访问或赋值的时刻,可以设置伴随被访问或被赋值时,执行其他函数。
js
  Object.defineProperty(obj, "address", {
    get: function() {
      bar()
      return this._address
    },
    set: function(val) {
      foo()
      this._address = val
    }
  })
  console.log(obj.address) // got address value once
  obj.address = "Shanghai" // resetted address value once
  function bar() {
    console.log("got address value once")
  }
  function foo() {
    console.log("resetted address value once")
  }
  Object.defineProperty(obj, "address", {
    get: function() {
      bar()
      return this._address
    },
    set: function(val) {
      foo()
      this._address = val
    }
  })
  console.log(obj.address) // got address value once
  obj.address = "Shanghai" // resetted address value once
  function bar() {
    console.log("got address value once")
  }
  function foo() {
    console.log("resetted address value once")
  }

Released under the MIT License.