Object.defineProperty 深入浅出(一、基础篇)

1,895 阅读3分钟

Object.defineProperty 在当前很多框架的实现中都使用了它的特性来实现,我们准备写一系列文章来深入浅出的了解下,第一篇文章先大概熟悉并了解整个方法参数以及使用方式。

Object.defineProperty —— 基础篇

Object.defineProperty —— 实战篇

方法定义

简单来说Object.defineProperty 实现的就是在一个对象上定义一个新属性,或者是修改一个已经存在的属性

Object.defineProperty(obj, prop, descriptor)

参数

obj
要定义属性的对象
prop
要定义或修改的属性的名称或 Symbol 
descriptor
要定义或修改的属性描述符

类型属性

这里根据 MDN 上,将defineProperty可以定义的两类属性分别分析下,一个是数据描述符、一个是存取描述符,并且这两种形式是不可以混用的。他们有共有属性和特有属性,我们下面都单独理一下。

描述符中属性默认参数

属性名称默认值
configurablefalse
enumerablefalse
valueundefined
writablefalse
getundefined
setundefined

数据描述符

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

value

let Obj = {}
Object.defineProperty(Obj, 'name', {
	value: 'chencc',
    writable: true // 是否可以改变
})

writable 是否可以改变属性的值

let Obj = {}
Object.defineProperty(Obj, 'name', {
	value: 'chencc'
})
Obj.name = 'chenhh'
// writable 默认值是false,则属性值无法改变
console.log(Obj.name)	// 'chencc'
let Obj = {}
Object.defineProperty(Obj, 'name', {
	value: 'chencc',
    writable: true
})
Obj.name = 'chenhh'
console.log(Obj.name)	// 'chenhh'

存取描述符

getter: 是一种获得属性值的方法 默认为 undefined

setter: 是一种设置属性值的方法 默认为 undefined

  let Obj = {}
  let temp = null
  Object.defineProperty(Obj, 'name', {
      get: function () {
          return temp
      },
      set: function (value) {
          temp = value
      }
  })
  Obj.name = 'chencc'
  console.log(Obj.name)	// 'chencc'

备注:在 get 和 set 设置对象的时候,需要设置一个 temp 的临时变量,都是通过临时变量赋值和改变值的方式,来改变

共有属性

configurable 是否可以删除

configurable 设置属性是否可以删除以及属性是否可以重新定义

eg1:
let Obj = {}
Object.defineProperty(Obj, 'name', {
	value: 'chencc',
	configurable: false,
    writable: true
})
Obj.name = 'chenhh'			// chenhh
delete Obj.name				// false 无法删除属性
eg2:
let Obj = {}
Object.defineProperty(Obj,'name', {
	value: 'chencc',
	configurable: false
})
Object.defineProperty(Obj, 'name', {
	value: 'chenhh'
})
//  Cannot redefine property: name

这里实际上是 configurable 和 writable 同时为 false 了

eg3:
let Obj = {}
Object.defineProperty(Obj, 'name', {
	value: 'chencc',
	configurable: true,
    writable: false
})
Obj.name = 'chenhh'
console.log(Obj.name)	// 'chencc'

Object.defineProperty(Obj, 'name', {
	value: 'chenhh'
})
console.log(Obj.name)	// 'chenhh'

如果 configurable 为真,writable 为假,直接给属性无法赋值,但是可以通过重新定义的方式进行赋值,并且可以删除属性

eg4:
let Obj = {}
Object.defineProperty(Obj, 'name', {
	value: 'chencc',
	configurable: false,
    writable: true
})
Object.defineProperty(Obj, 'name', {
	value: 'chenhh'
})
总结
  • configurable 为 false时,不能删除属性,且不能重新设置属性的描述(除了writable例外,可以把writable由 true 改为 false,但是无法将 writable 由 false 改为true),同时在 writable 为 true 的时候,可以修改 value 的值

enumerable 是否可以枚举

let Obj = {}
Object.defineProperty(Obj, 'name', {
	value: 'chencc',
    enumerable: false
})

Obj.subject = 'CS'

Object.defineProperty(Obj, 'age', {
	value: 25,
    enumerable: true
})

console.log(Object.keys(Obj))		// ['subject', 'age']

for (let key in Obj) {
	console.log(key)
}
// subject
// age

Obj.propertyIsEnumerable('subject')		// true
Obj.propertyIsEnumerable('age')			// true
Obj.propertyIsEnumerable('name')		// false

备注:写法的区别

eg1:
let Obj = {}
Obj.name = 'chencc'
// 等同于
Obj.defineProperty(Obj, 'name', {
	value: 'chencc',
    configurable: true,
    writable: true,
    enumerable: true
})
eg2
let Obj = {}
Object.defineProperty(Obj, 'name', {
	value: 'chencc'
})
// 等同于
Obj.defineProperty(Obj, 'name', {
	value: 'chencc',
    configurable: false,
    writable: false,
    enumerable: false
})

总的来说,对于defineProperty对象的基础部分主要在两种描述和几个属性定义,大家把这个理解清楚就可以对于这些来做一些实际应用了。