Object.defineProperty初体验

首先是 MDN 的解释:

Object.defineProperty()方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。

对于 Object.defineProperty 早有耳闻,比如 Vue 就依赖此方法来实现数据响应。最近在 ajax-hook 中也发现了此方法的身影,于是也来探体验一番。

试验代码

const cat = {
  name: 'Tom',
  age: 3
}
const testObj = {}

// configurable enumerable writable 都为 true
testObj.name = 'Jack'
// configurable enumerable writable 都为默认值 false
Object.defineProperty(testObj, 'age', {
  value: 8
})

console.log(Object.getOwnPropertyDescriptor(testObj, 'name'))
console.log(Object.getOwnPropertyDescriptor(testObj, 'age'))

// delete testObj.name // true
// delete testObj.age  // false

Object.defineProperty(testObj, 'someObj', {
  value: {
    num: 1
  },
  enumerable: true,
  configurable: true,
  writable: false
})

simpleSet(cat, 'name', 'nick')
simpleSet(testObj, 'str', 'test')
simpleSet(testObj, 'other', 'writable')
simpleSet(testObj, 'age', 18) // error

// testObj.age = 3              // not changed
// testObj.someObj = { num: 3 } // not changed
// testObj.someObj.num = 3      // changed..
// testObj.other = 3            // changed

console.log('cat', cat)
console.log('testObj', testObj)
// 不包含 age 属性
console.log('all of the properties', Object.keys(testObj)) // or use `for in`
// 返回一个由指定对象的所有自身属性的属性名组成的数组
// `包括不可枚举属性`,不包括Symbol值作为名称的属性
console.log('getOwnPropertyNames', Object.getOwnPropertyNames(testObj))

function simpleSet(obj, key, val) {
  let value = val
  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function() {
      console.log('getter:', key, value)
      return value
    },
    set: function(v) {
      console.log('setter:', key, v)
      value = v
    }
  })
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

在 Chrome Console 中的样子

console

几个比较重要的点:

  • value 与 get, set 不可共存
  • 一旦使用 Object.defineProperty 来定义属性,未配置的描述符将为默认值,与直接赋值不同
  • Object.defineProperty 可以重新定义 configurabletrue 的属性