JS對象屬性中get/set與getter/setter是什么


在js屬性描述符這部分有幾個較難理解的名詞概念,本文旨在描述對它們的理解,主要包括:[[Get]]/[[Put]]get/setgetter/setter幾個概念的闡述,數據屬性訪問器屬性

屬性

首先我們要搞清楚屬性的概念,屬性是存儲在特定命名位置的值,是對象的內容,屬性並不直接存儲在對象容器內部。屬性有兩種類型:數據屬性和訪問器屬性。屬性具備了屬性描述符,用來描述屬性擁有的特性。

屬性描述符

屬性描述符用來描述屬性特性的(只有在內部才能用的特性),配置屬性是否可讀,是否可寫,是否可枚舉,值是多少,讀寫。

屬性描述符對象

Object.definePrOperty(obj, 'a', { value:2, writable:true, configurable:true })

第三個參數就是屬性描述符對象 ,首先它是個對象,它有自己的屬性,其次它是屬性a的屬性描述符,用來配置屬性。

定義這些特性為了實現JavaScript引擎用的,因此再JavaScript中不能直接訪問它們。為了表示特征是內部值,ES規范把它們放在了兩對方括號中,例如[[Enumerable]]。

訪問器屬性不能直接定義,必須使用Object.defineProperty()來定義。

數據屬性

  • 數據屬性包含一個數據值的位置。在這個位置可以讀取和寫入值。共有四個描述其行為的特征:
    • [[Configurable]]:配置,表示能否刪除修改屬性的特性,或者把屬性修改為訪問器屬性。默認true
    • [[Enumerable]]:枚舉,表示能否通過for-in循環返回屬性。默認true
    • [[Writable]]:可寫,表示能否修改屬性值。默認true
    • [[Value]]:屬性的數據值。讀寫屬性值從該位置。默認undefined

訪問器屬性

  • 訪問器屬性不包含數據值;它們包含一對getter和setter函數。共有四個描述其行為的特征:
    • [[Configurable]]:配置,表示能否刪除修改屬性的特性,或者把屬性修改為訪問器屬性。默認true
    • [[Enumerable]]:枚舉,表示能否通過for-in循環返回屬性。默認true
    • [[Get]]:在讀取屬性值時調用的函數。默認undefined
    • [[Set]]:在寫入屬性值時調用的函數。默認undefined

當個一個屬性定義getter、setter或者兩者都有時,這個屬性就成了訪問器屬性

知道屬性分類之后,下面我們逐一解答開頭的幾個問題:

[[Get]]/[[Put]]是什么

首先要明確一點,[[Get]]和[[Put]]是對象默認的內置操作,可以理解為算法函數。它是在訪問屬性時的操作,例如通過obj.a訪問a屬性時就是實現了[[Get]]操作,它會先找到相同的屬性名,找到才要返回屬性值。

沒有找到就會按照[[Get]]算法的設計,沿着原型鏈找,找不到會返回undefined。

[[Put]]被觸發時,取決於許多因素,最重要的有對象中是否已經存在這個屬性。如果已經存在,算法大致會檢查下面這些內容:

屬性是否是訪問描述符?如果是並且存在setter就調用setter
屬性的數據描述符中writable是否是false?如果是,在非嚴格模式下靜默失敗,在嚴格模式下拋出TypeError異常。
如果都不是,將該值設置為屬性的值。

get/set和getter/setter

[[Get]]和[[Set]]:當屬性擁有這兩個特性時,屬性就是訪問器屬性。代表着在訪問屬性或者寫入屬性值時,對返回值做附加的操作。而這個操作就是getter/setter函數。

它們只能應用到單個屬性上,無法應用在整個對象上。getter/setter是隱藏函數,是訪問器屬性默認擁有的隱藏函數。在讀取訪問器屬性時調用getter,返回有效的值;在寫入訪問器屬性時調用setter函數並傳入新值。

不管是對象文字語法中的get a(){...},還是的defineProperty(..)中的顯式定義,二者都會在對象中創造一個不包含值得屬性,對於這個屬性的訪問會自動調用一個隱藏函數,它的返回值會被當做屬性訪問的返回值:

javascript
var myObject = {
//給a定義一個getter
get a(){
return this._a_;
},
//給a定義一個setter
set a(val){
this._a_=val *2;
}
}
myObject.a=2;
myObject.a;//4

設置getter會覆蓋默認的[[Get]]操作,setter會覆蓋默認得[[Put]],也被稱為賦值操作

實際上我們賦值([[Put]])操作中的值2存儲到了另一個變量_a_中。名稱_a_只是一種慣例,沒有任何特殊行為。

總結

屬性是擁有自己的特性的,主要用來描述屬性是否可以進行修改枚舉配置的。我們訪問對象的屬性時就是[[Get]]操作,寫入就是[[Put]]操作,根據算法找到對應的屬性。如果要對屬性值進行附加操作時,就需要設置get/set特性,此時屬性也就會變成訪問器屬性,然后調用默認的隱藏的getter/setter函數對屬性進行操作。然后返回屬性值。這就是整個流程,vue框架中雙向綁定就是用到了這些概念來完成數據監聽的,對象屬性可以說是js中一個很核心的概念了。

本文是陳少棠原創,收錄在《齊雲札記》,轉載請標明原作。

參加博客:https://baijiahao.baidu.com/s?id=1623144714605018773&wfr=spider&for=pc


免責聲明!

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



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