在講到Obeject.defineProperty()方法以前先得說明一下ECMAScript中有兩種屬性:數據屬性和訪問器屬性。 javascript
兩種屬性存在的意義:描述對象屬性(key)的一些特性,由於這些屬性是內部值,通常放到 [[兩個中括號]] 中。vue
Object.defineProperty(obj , 'key' , {描述信息,是個對象,相似配置項} ) 方法接收三個參數,屬性所在的對象,屬性名 和一個描述符對象。java
數據屬性的描述符是下面的一個或者多個(configurable、enumerable、writable 和 value)數組
訪問器屬性的描述符是如下的一個或多個(configurable、enumerable、get 和 set)框架
經過 Object.defineProperty()
方法,能夠建立數據屬性(並設定其內部屬性),也能夠建立訪問器屬性(訪問器屬性包含 getter
和 setter
函數)函數
數據屬性的各項解釋:spa
enumerable : 可枚舉性,是否能經過for-in或者Object.keys來遍歷prototype
writable : 可修改(可寫入),是否能修改value屬性值3d
value : 屬性的屬性值 (讀出和寫入都是從這裏讀出和保存的),默認undefined 數據屬性是能夠直接經過 對象.屬性obj.key
的形式訪問和賦值的雙向綁定
configurable : 是否可配置,當它爲false的時候,一、上面三項的true和false值都不能改變了,二、對象自己也不能經過delete來刪除三、數據屬性和訪問器屬性也不能來回轉化了
訪問器屬性的各項解釋:
configurable 、enumerable同上
get : 讀取屬性的時候調用,默認值undefined
set : 設置屬性的時候調用,默認值undefined
對比數據屬性和訪問器屬性的屬性異同
數據屬性做用: 修改屬性默認的特性 (會新建出數據屬性)
訪問器的做用: 訪問和設置數據屬性的屬性值,不會建立出 .
一、對象屬性的建立對比----- 這裏建立的是數據屬性不是訪問器屬性,訪問器屬性只有一種建立方式
A、字面量建立對象的形式:var obj = {key : value } ------ var person1 = {age : 3} 直接建立了age屬性和屬性值
B、Object.defineProperty(obj ,'key' {...} )建立對象 ------ var person2 = {}; Object.defineProperty(person2, "age", { value: 3 });
經過統一的操做 :
① console.log(person1 .name) ② person1.age = 4 ③ console.log(person1 .name) 得出 // 3 , 4 賦給了新的值
① console.log(person2 .name) ② person2.age = 4 ③ console.log(person2 .name) 得出 // 3 , 3 賦值沒有成功
原理:
直接在對象上定義的屬性var obj = {key : value }(字面量形式和new Object()形式
) ,它們的Configurable、Enumerable 和Writable特性都被設置爲 true,而Value特性被設置爲指定的值
經過 Object.defineProperty()定義的屬性 它們的Configurable、Enumerable 和Writable特性都被設置爲 false,而Value特性被設置爲指定的值,這時候的屬性值是隻讀的
二、重點:數據屬性不只能夠直接訪問和設置(對象.屬性/obj.key的形式),也能夠經過定義的訪問器(getter setter)來專門訪問和設置。
得出結論:
① 經過發現book下面並無真正的year屬性,證實了數據屬性並不能根據訪問器屬性來定義建立,訪問器屬性只是操做訪問器屬性,這個屬性能夠理解爲是在get和set這一動態讀取和設置的過程當中發揮做用。
② set
和get
是一對勾子(hook)函數,要理解觸發機制(是根據調用book.year或者設置book.year=2005這個時間點觸發的,因此這個year能夠隨便取值):就是訪問器屬性在調用時,實際上對應觸發訪問器屬性中定義的 get
方法(最後返回的值是其中return出來的結果),當對一個對象的某個屬性賦值時,則會自動觸發調用相應的set
函數。(若是不瞭解運行機制,須要打斷點走一遍便可)
③ book只有_year和edtion兩個數據屬性(是否是數據屬性,要看帶不帶value屬性),year不是數據屬性(訪問屬性不包含數據值,也不會顯式的寫出來),可是可是book.hasOwnProperty("year");
確實返回 true
。說明了訪問器屬性也屬於對象本身添加的屬性。只是讀寫方式和普通的不同。
三、再來擼一遍代碼,看看運行的原理具體是怎樣的??
四、怎麼區分數據屬性仍是訪問器屬性???看裏面的描述符對象。二者是不能混用的。
五、js中的屬性的理解:
javascript中一共有三種屬性:
普通屬性:也就是常規的數據屬性,這種屬性是用戶來添加修改等,把它設置成什麼樣,就返回出來什麼樣,不會作些額外的事情。 var obj ={name : "yang"};那麼console.log(obj.name) //yang
內部屬性:好比數組arr的length屬性,函數的prototype屬性,DOM節點的innerHTML屬性,用戶賦完值之後,取值的時候,不必定按預期,有時候還會額外的作一些事情,也難以改變他們的行爲。
好比說某一數組,它的長度爲10, 當咱們設置它爲11時,它就會增長一個undefined元素,再設置爲9時,就會從後面刪掉兩個元素。
函數的prototype若是被改變,至關於將其父類改變了,會new不一樣類型的實例。
DOM的innerHTML,咱們賦值時是一個字符串,再取出時,這字符串可能會與原來的不同, 而且在原元素上生成了不同的子節點。
訪問器屬性,容許用戶在賦值或取值都通過預先設定的函數,從而實現內部屬性的那一種特殊效果。
六、應用(能夠代替對象中的getter和setter函數)
==
其餘地方:vue框架MVVM的數據雙向綁定,數據的實時觀察,不一樣於angular使用的髒檢查。
七、和Object.defineProperty()相關的一些對象方法。
obj.propertyIsEnumerable('key')
obj.hasOwnProperty('key') 能夠檢測出訪問器屬性
Obeject.getOwnpropertyDescriptor(obj , 'key') 或者描述符對象 ----- 有就返回對象,不然是undefined。
Object.keys(obj)方法,遍歷key值 。 當Object.defineProperty()中enumerable爲false的時候,是遍歷不出來的。
八、其餘
Obeject.prototype的configurable是false,表明不可配置
對象obj的toString方法是原型鏈上的是不可枚舉的 obj.propertyIsEnumerable(toString') // false
最後:不要再IE8 及之前版本 中使用 Object.defineProperty()