iT邦幫忙

5

[筆記][JavaScript]由物件中設定「存取器」屬性

物件內的存取器是由getset去設定的,而存取器的設定可以用像是特性一樣的方式去使用他,他們兩者不同的地方是存取器屬性可以以getset去控制該特性被讀寫的功能,get就代表讀取,set則是寫入,擁有兩個屬性就可以同時被讀寫。

首先用get來控制一個存取器的讀取功能,以下實作:

//用get在物件obj內設定一個只能讀取的存取器name
var objA = {
    get name(){
        return 'objName';
    },
};
//讀取name會得到return的'objName'
objA.name; //回傳'objName'

//而雖然他能夠像特性般擁有值,但是實際上該物件是沒有這個特性的
objA; //回傳空物件{} 

//因為只有get的讀取屬性,沒有set的寫入,所以他無法設定值
objA.name = 'objA';  //將obj.name的值設定為'objA'

//所以在設定完後檢查該物件,一樣會是空的
objA; //回傳空物件{} 

接著我們再來只用set來控制一個存取器的寫入功能,setget設置的時候有個不同點,set必須擁有一個能夠傳進引數的變數,因為當我們在寫入值的時候,存取器會將我們設置的值放進該變數中,以下實作:

//用set在物件內設定一個只能寫入的存取器name,括號內的val就是設置的值傳入的位置,這裡我們讓存取器去寫入值到this.objName中,this指的是該物件,所以也就是為objB增加一個特性,讓我們設定的值指定objB.objName
var objB = {
    set name(val){
        this.objName = val;
    },
};

//為該存取器設置值
objB.name = 'objB';  //此時存取器中跑的程式為:objB.objName='objB'

//而我們試著去讀取存取器為我們新增的特性
objB.objName;  //會回傳'objB'

//但是因為沒有設置get所以他無法讀出該存取器擁有的值
objB.name; //回傳undefined

//當然該物件會出現存取器為我們設定的特性
objB; //回傳{objName: "objB"}

最後來同時使用getset讓該存取器同時擁有讀取及寫入的功能

//在物件內同時設定擁有讀取和寫入的存取器name,這次我們在get內讀取物件中的objName的值,並將他回傳
var objC = {
    get name(){
        return this.objName;
    },
    set name(val){
        this.objName = val;
    },
};

//讀取該存取器會得到undefined,因為我們還沒有為該特性objName指定值
objC.name;  //回傳'undefined'

//接著為該存取器設值'objC'
objC.name = 'objC';  //此時存取器會將'objC'指定給objC.objName

//再試著使用存取器讀出this.objName,也就是objC.objName試試
objC.name;  //會回傳'objC'

//最後再來看一下該物件目前的樣子
objC;  //會出現一個被存取器設置的特性{objName: "objC"} 

基本用法大概就是這樣,但是他和一般特性一樣,如果未用set設值前get是指會回傳undefined的,不過既然他的get中可以寫程式,那就可以想辦法克服這一點,例如:

//在get中加入判斷式,如果再讀取this.objName時,該特性不為undefuned的話就回傳該特性的值,但如果為undefined就回傳預設的'defaultName'
var objD = {
    get name(){
		if(this.objName){
			return this.objName
		}
		else{
        	return 'defaultName';
		}
    },
    set name(val){
        this.objName = val;
    },
};

//在不先設值的情況下去讀取存取器name,因為目前this.objName還是undefined,所以會回傳預設的'defaultName'
objD.name;  //回傳'defaultName'

//指定一個值給存取器name
objD.name = 'objD';

//再讀一次存取器name,因為這時候this.objName已經有被指定值,所以就會回傳特性本身的值'objD'
objD.name;  //會回傳'objD'

最後要注意的事情是,存取器的名稱不能和特性的名稱重複,否則設置時會發生錯誤,例如:

//如果我們在get和set中都用和存取器本身重複的名稱,那不論讀取或寫入都會出錯
var objE = {
    get name(){
        return this.name;
    },
    set name(val){
        this.name = val;
    },
};

//讀取該存取器的值
objE.name;  //會出錯'RangeError'!!!

//設置該存取器的值
objE.name = 'objE';  //還是會出錯'RangeError'!!

以上對於存取器的說明,如果我有觀念錯誤或解釋不清楚的地方,還麻煩各位大大指點了,謝謝大家!


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 則留言

0
小碼農米爾
iT邦高手 1 級 ‧ 2018-03-19 15:31:57

很像 C# 的屬性,這好像是 ES6 的東西,
看了一下瀏覽器支援度,IE9 以上的瀏覽器都支援,
可以考慮用在專案上,哈哈。
/images/emoticon/emoticon35.gif

神Q超人 iT邦研究生 5 級 ‧ 2018-03-26 00:46:25 檢舉

對啊!我和我朋友分享的時候他也說很像
是ES6嗎!!!我一直以為是ES5的/images/emoticon/emoticon17.gif

我的資訊錯誤,getter setter 是 ES5 的
/images/emoticon/emoticon25.gif

0
tacodrem
iT邦新手 5 級 ‧ 2018-05-31 15:48:26

不好意思,請問一下存取器一般是常用在何種情境上?
似乎除了隱密性以外,有什麼比較需要選擇這種寫法的情況嗎?
謝謝

看更多先前的回應...收起先前的回應...
神Q超人 iT邦研究生 5 級 ‧ 2018-08-02 15:46:49 檢舉

對不起!!!!我沒有留意到這個留言!!!!
等我下班在回覆您!!!!真的不好意思!!!

tacodrem iT邦新手 5 級 ‧ 2018-08-03 09:18:21 檢舉

哈哈~沒關係!!
感謝大大~
其實我自己都忘記這篇留言了XDD

神Q超人 iT邦研究生 5 級 ‧ 2018-08-06 23:10:40 檢舉

我突然需要這個回頭看自己文章才發現XD
我昨天剛北漂回來,哈哈!

存取器對物件來說是個很方便的東西,其實他就很像C#中的gettersetter
能做到的事情就像像大大提到的對不直接操作屬性,讓物件具有隱密性之外,
也可以把console.log放在get或set中方便做測試看值,
而且如果一開始沒有物件設定該屬性的時候,也能夠利用get來讓屬性直接擁有預設值,

以及因為JavaScript是動態型別,當然物件裡面的屬性也是,所以當我們在設值的時候能夠再set中做簡單的判斷,讓該屬性的類型不會輕易發生改變!

tacodrem iT邦新手 5 級 ‧ 2018-08-07 09:12:16 檢舉

喔喔~!!
感謝大大回覆!!

我要留言

立即登入留言