JavaScript 學習筆記 之 對象 (三) - [[Get]]和[[Put]]操作

[[Get]]

對對象屬性的訪問看起來似乎是一件很簡單的事

但事實上這裏有個複雜的[[Get]]操作在裏面(可以理解爲函數調用[[Get]]() )

對象默認的內置[[Get]]操作首先是在對象中查找是否有名稱相同的屬性,有則返回這個屬性的值

如果沒有找到,則會遍歷可能存在的[[Prototype]]鏈(也就是原型鏈,之後我會專門再出一系列博客來介紹這個)

如果無論如何都沒找到,name就返回一個undefined值

如果你還記得我在寫關於作用域的學習筆記的話,你可能會發現這裏跟變量訪問(RHS查詢)有點不太一樣

變量訪問沒找到的話會拋出一個ReferenceError異常,而對象屬性的訪問沒找到則會返回一個undefined值

不過這裏有個問題

如果屬性設置的值就是undefined呢?

所以直接通過返回值無法判斷這個屬性是否存在,但是有另外的方法可以判斷(in,hasOwnProperty(..),稍後會詳細介紹)

[[Put]]

[[Put]]操作並不僅僅只是給對象設置或者創建一個屬性

[[Put]]被觸發時,實際行爲取決於許多因素,但是最重要的因素是對象中是否已經存在這個屬性

如果存在這個屬性,[[Put]]會檢查一下內容

  1. 屬性是否是訪問描述符(接下來會講到)?如果是並存在setter就調用setter
  2. 屬性的數據描述符中的writable參數
  3. 如果都不是,則將該值設定爲屬性的值

如果不存在的話,那麼操作會更加複雜,這個我們在講原型鏈的時候再詳細討論

訪問描述符

屬性不一定包含的是值

他們可能是具備getter/setter的"訪問描述符"

在ES5中可以使用getter和setter來部分改寫默認操作,但是隻能應用在單個屬性上

getter和setter都是隱藏函數,會做獲取和設置函數值的時候調用

當年給一個屬性定義setter和getter時,這個屬性會被定義爲訪問描述符

而此時JavaScript將會忽略屬性(數據描述符中)的value和writable特性,而關心set和get(還有configurable和enumerable特性)

		var obj = {
			get a() {
				return 2;
			}
		}
		obj.a = 10086
		console.log(obj.a); //2

由於get和set同樣是屬性描述符(數據描述符和訪問描述符)中,我們也可以用定義屬性描述符的方式來定義他們

		var obj = {
			a: 1
		}
		Object.defineProperty(obj, "a", {
			get: function() {
				return 233
			},
			enumerable: true //確保a會出現啊屬性列表中
		});
		obj.a = 111;
		console.log(obj.a); //233

這兩種方式都會在對象中創建一個不包含值的屬性 a,對於這個屬性a 的訪問會自動調用一個隱藏函數,他的返回值會被當做屬性訪問的返回值

由於我們只定義了getter,所以對a的值進行設置時set會忽略賦值操作,不會拋出錯誤

setter方法的設置跟getter是一樣的,不過他接受一個參數,也就是賦值操作傳遞進去的參數

		var obj = {
			a: 1
		}
		Object.defineProperty(obj, "a", {
			get: function() {
				return this._a_;
			},
			set: function(val) {
				this._a_ = val + ",這是setter設置的"
			}
		});
		obj.a = 111;
		console.log(obj.a); //111,這是setter設置的

注 : 這個案例中的_a_只是一種慣例,其實在對象內創建了一個新的值,沒有任何特殊的行爲

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章