Object.defineProperty
是ES5新增的一个API,其做用是给对象的属性增长更多的控制。在咱们平常的coding中,这个API用到的地方很少,然而它对于MVVM框架中双向数据绑定(two-ways data binding)来讲是相当重要的一个API,目前vue和avalon中的双向数据数据绑定均是经过它来实现的。vue
Object.defineProperty
方法提供了一种直接的方式来定义对象属性或者修改已有对象属性。git
Object.defineProperty(obj, prop, descriptor)
obj: 须要定义属性的对象(目标对象)github
prop: 需被定义或修改的属性名(对象上的属性或者方法)app
descriptor: 需被定义或修改的属性的描述符框架
obj
和prop
都比较好理解,咱们重点来解析第三个参数属性描述符,它是一个对象,里面有如下取值:函数
value: 属性的值spa
var a = {} Object.defineProperty(a, 'b', { value: 2 }) console.log(a.b); // => 2
writable: 属性是否能被重写(rewrite),默认为false
code
var a = {} Object.defineProperty(a, 'b', { value: 2, writable: false }) console.log(a.b); // output 2 a.b = 3 console.log(a.b); // still ouput 2
enumerable: 属性是否能在for ... in
或者Object.keys
中被枚举出,来默认为false
对象
var a = {} Object.defineProperty(a, 'b', { value: 2, enumerable: false }) console.log(Object.keys(a)) // output [] Object.defineProperty(a, 'c', { value: 2, enumerable: true }) console.log(Object.keys(a)) // output ['c']
configurable: 是否可以配置value
,writable
,configurable
,默认为false
blog
var a = {} Object.defineProperty(a, 'b', { value: 2, enumerable: false }) console.log(a.b) // output 2 Object.defineProperty(a, 'b', { value: 3, enumerable: true }) // TypeError: Cannot redefine property: b
get: 一个给属性提供 getter 的方法,默认undefined
set: 一个给属性提供 setter 的方法,默认undefined
属性描述符分为数据描述符和存取描述符。数据描述符是一个拥有可写或不可写值的属性。存取描述符是由一对 getter-setter 函数功能来描述的属性。
数据描述符和存取描述符均具备可选键值:configurable
, enumerable
数据描述符同时具备可选键值:value
,writable
,get
,set
用思惟导图来表示就是:
对于set
和get
,个人理解是它们是一对勾子(hook)函数,当你对一个对象的某个属性赋值时,则会自动调用相应的set
函数;而当获取属性时,则调用get
函数。这也是实现双向数据绑定的关键。
var a = {} var b Object.defineProperty(a, 'b', { get: function() { console.log('get b') // 咱们能够在这里对返回的值作任何操做 return b + 1 }, set: function(newValue) { console.log('set b to', newValue) b = newValue } }) a.b = 100 console.log(a.b); /* output: set b to 100 get b 101 */
数据描述符和存取描述符不能混合使用
Object.defineProperty(o, "conflict", { // value是数据描述符 value: 1, // get是存取描述符 get: function() { return 2; } }); // throws a TypeError: value appears only in data descriptors, get appears only in accessor descriptors