Javascript中對象的Obeject.defineProperty()方法-------------(ES5/個人理解)


在講到Obeject.defineProperty()方法之前先得說明一下ECMAScript中有兩種屬性:數據屬性訪問器屬性 

兩種屬性存在的意義:描述對象屬性(key)的一些特性,因為這些屬性是內部值,一般放到 [[兩個中括號]]  中。

 

Object.defineProperty(obj , 'key' , {描述信息,是個對象,類似配置項} )  方法接收三個參數,屬性所在的對象屬性名 和一個描述符對象

數據屬性的描述符是下面的一個或者多個(configurable、enumerable、writable 和 value)

訪問器屬性的描述符是以下的一個或多個(configurable、enumerable、get 和 set)

 

通過 Object.defineProperty() 方法,可以創建數據屬性(並設定其內部屬性),也可以創建訪問器屬性(訪問器屬性包含 getter 和 setter函數)

 

數據屬性的各項解釋:

enumerable : 可枚舉性,是否能通過for-in或者Object.keys來遍歷

 

writable : 可修改(可寫入),是否能修改value屬性值

 

value : 屬性的屬性值  (讀出和寫入都是從這里讀出和保存的),默認undefined    數據屬性是可以直接通過  對象.屬性obj.key 的形式訪問和賦值

 

configurable : 是否可配置,當它為false的時候,1、上面三項的true和false值都不能改變了,2、對象本身也不能通過delete來刪除3、數據屬性和訪問器屬性也不能來回轉化了

 

 

訪問器屬性的各項解釋:

configurable 、enumerable同上

get : 讀取屬性的時候調用,默認值undefined

set : 設置屬性的時候調用,默認值undefined

 

對比數據屬性和訪問器屬性的屬性異同

 

數據屬性作用:   修改屬性默認的特性 (會新建出數據屬性)

訪問器的作用:  訪問和設置數據屬性的屬性值,不會創建出  .

 

1、對象屬性創建對比-----   這里創建的是數據屬性不是訪問器屬性,訪問器屬性只有一種創建方式

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特性被設置為指定的值,這時候的屬性值是只讀的

 

 

 

2、重點:數據屬性不僅可以直接訪問和設置(對象.屬性/obj.key的形式),也可以通過定義的訪問器(getter setter)來專門訪問和設置

 

得出結論:

① 通過發現book下面並沒有真正的year屬性,證明了數據屬性並不能根據訪問器屬性來定義創建,訪問器屬性只是操作訪問器屬性,這個屬性可以理解為是在get和set這一動態讀取和設置的過程中發揮作用。

setget是一對勾子(hook)函數,要理解觸發機制(是根據調用book.year或者設置book.year=2005這個時間點觸發的,所以這個year可以隨便取值):就是訪問器屬性在調用時,實際上對應觸發訪問器屬性中定義的 get 方法(最后返回的值是其中return出來的結果),當對一個對象的某個屬性賦值時,則會自動觸發調用相應的set函數。(如果不了解運行機制,需要打斷點走一遍即可)

③ book只有_year和edtion兩個數據屬性(是不是數據屬性,要看帶不帶value屬性),year不是數據屬性(訪問屬性不包含數據值,也不會顯式的寫出來),但是但是book.hasOwnProperty("year"); 確實返回 true。說明了訪問器屬性也屬於對象自己添加的屬性。只是讀寫方式和普通的不一樣。

④ _year帶有下划線的屬性,表示只能通過  對象方法 訪問的屬性。( 有待補充。。。。)

 

3、再來擼一遍代碼,看看運行的原理具體是怎樣的??

 

訪問器將真正存值的變量隱藏起來,並提供對外的接口,當你讀取或設置屬性時,可執行一定的操作:
 

 

上列中set的參數就是你設置的值。從外部看,你設置man.age的方式與賦值無異,這與el.style.color = "red"相似:看上去是簡單的賦值,卻觸發了一定行為(設置DOM文本為紅色)。

  

4、怎么區分數據屬性還是訪問器屬性???看里面的描述符對象。兩者是不能混用的。

 

 

5、js中的屬性的理解: 

javascript中一共有三種屬性:

普通屬性:也就是常規的數據屬性,這種屬性是用戶來添加修改等,把它設置成什么樣,就返回出來什么樣,不會做些額外的事情。 var obj ={name : "yang"};那么console.log(obj.name) //yang

內部屬性:比如數組arr的length屬性,函數的prototype屬性,DOM節點的innerHTML屬性,用戶賦完值以后,取值的時候,不一定按預期,有時候還會額外的做一些事情,也難以改變他們的行為。

    比如說某一數組,它的長度為10, 當我們設置它為11時,它就會增加一個undefined元素,再設置為9時,就會從后面刪掉兩個元素。

    函數的prototype如果被改變,相當於將其父類改變了,會new不同類型的實例。

    DOM的innerHTML,我們賦值時是一個字符串,再取出時,這字符串可能會與原來的不一樣, 並且在原元素上生成了不一樣的子節點。

訪問器屬性,允許用戶在賦值或取值都經過預先設定的函數,從而實現內部屬性的那一種特殊效果。

 

6、應用(可以代替對象中的getter和setter函數)

    ==    

 

其他地方:vue框架MVVM的數據雙向綁定,數據的實時觀察,不同於angular使用的臟檢查。

 

 7、和Object.defineProperty()相關的一些對象方法。

obj.propertyIsEnumerable('key')

obj.hasOwnProperty('key')    可以檢測出訪問器屬性

Obeject.getOwnpropertyDescriptor(obj , 'key')   或者描述符對象  -----   有就返回對象,否則是undefined。

Object.keys(obj)方法,遍歷key值 。   當Object.defineProperty()中enumerable為false的時候,是遍歷不出來的。

 

8、其他

Obeject.prototype的configurable是false,代表不可配置

對象obj的toString方法是原型鏈上的是不可枚舉的   obj.propertyIsEnumerable(toString')     // false 

  

 

最后:不要再IE8 及以前版本 中使用 Object.defineProperty() 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM