参考链接:深入浅出Object.defineProperty Object.defineProperty - 图1

一、语法

Object.defineProperty的作用就是直接在一个对象上定义一个新属性,或者修改一个已经存在的属性

  1. Object.defineProperty(obj, prop, desc)
  2. Object.defineProperties(obj, {
  3. prop1: desc,
  4. prop2: desc
  5. })
  • obj 是需要定义属性的当前对象
  • prop 为当前需要定义的属性名
  • desc 为属性描述符

一般通过为对象的属性赋值的情况下,对象的属性可以修改也可以删除,但是通过Object.defineProperty定义属性,通过描述符的设置可以更加精确的控制对象属性。

JavaScript有三种类型属性

  • 命名数据属性:Obj.name = ‘xxx’
  • 命名访问器属性:通过 gettersetter 进行读取和赋值的属性
  • 内部属性:例如 [[Prototype]]

二、数据描述符&存取描述符

通过Object.defineProperty()为对象定义属性,有两种形式,且不能混合使用。分别为数据描述符、存取描述符。

数据描述符(value, writable)

数据描述符特有的两个属性: value writable

value就是属性的值,writable表示是否可以修改

  1. let person = {}
  2. Object.defineProperty(person, 'name', {
  3. value: 'zx',
  4. writable: false // 是否可以修改(这里不允许修改)
  5. })
  6. person.name = 'tzq'
  7. console.log(person.name) // zx

存取描述符(set, get)

get : 一个给属性提供getter的方法,如果没有getter则为undefined。该方法返回值被用作属性值。
set : 一个给属性提供setter的方法,如果没有setter则为undefined。该方法将接受唯一参数,并将该参数的新值分配给该属性。

  1. let person = {}
  2. Object.defineProperties(person, {
  3. _name: {
  4. value: 'zx',
  5. writable: true
  6. },
  7. name: {
  8. get: function() {
  9. console.log('getter被调用了!!')
  10. return this._name
  11. },
  12. set: function(val) {
  13. console.log('setter被调用了!!')
  14. this._name = val
  15. }
  16. }
  17. })
  18. person.name = 'tzq' // getter被调用了!!
  19. console.log(person.name) // setter被调用了!! tzq

注意点: get必须要return;并且必须return一个变量,否则无法改变改属性值,写死没有任何意义。
set方法是在对象该属性被修改时触发,用于修改属性值

公共描述符(configrable, enumerable)

  • configrable 描述属性可否删除,以及可否再次配置 ```javascript “use strict” let person = {} Object.defineProperty(person, ‘name’, { value: ‘jack’, configurable: false })

delete person.name // cannot delete property ‘name’ of # 无法删除

Object.defineProperty(person, ‘name’, { value: ‘rose’ }) // Cannot redefine property: name

  1. <br />
  2. - enumerateable 描述属性是否会出现在for in 或者 Object.keys()的遍历中
  3. ```javascript
  4. let obj = {}
  5. Object.defineProperties(obj, {
  6. name: {
  7. value: 'zx',
  8. writable: true,
  9. configurable: false,
  10. enumerable: true
  11. },
  12. age: {
  13. value: 22,
  14. writable: true,
  15. configurable: false,
  16. enumerable: true
  17. },
  18. sex: {
  19. value: 'male',
  20. writable: true,
  21. configurable: false,
  22. enumerable: false
  23. }
  24. })
  25. console.log(Object.keys(obj)) // [ 'name', 'age' ]

写在最后

如果写了Object.defineProperty,如果描述符中某些属性被省略,会使用以下默认规则
image.png
记住下面两种形式的区别

1、直接声明

  1. let obj = {}
  2. obj.name = 'Jack'
  3. // 上面代码等价于
  4. let obj = {}
  5. Object.defineProperty(obj, name, {
  6. value: 'Jack',
  7. enumerable: true,
  8. configureable: true,
  9. writable: true
  10. })

这种声明方式就默认三个属性都是true,在不写defineProperty的情况下

2、使用Object.defineProperty声明

  1. Object.defineProperty(obj, 'name', {
  2. value: 'Jack'
  3. })
  4. // 上面代码等价于
  5. Object.defineProperty(obj, 'name', {
  6. value: 'Jack',
  7. enumerable: false,
  8. configureable: false,
  9. writable: false
  10. })

defineProperty要么不写,写了其他三个属性不写的话默认都是false