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