JavaScript 內的物件都有內建的兩個屬性,可以實現對物件的存取,稱為:
不同於一般物件內的屬性,由 getter 和 setter 定義的屬性有個專有名詞稱為 存取器屬性 accessor property。
寫在 getter 或 setter 的屬性皆為方法,但在查找時,不需加上()
呼叫,背後會自動進行函式呼叫。
兩者的差異?
getter 取值器,主要目的是讀取值,不能進行賦值修改。
setter 設值器,可以設定屬性的值,透過賦值的方式傳入參數。
屬性依照是否設置 setter 與 getter 分為三種特性:
在 JS 中有三種方法:
//物件實質中的寫法
let obj = {
get name(){
....
},
set name(value){
...
}
}
setter、getter 可用來定義可計算屬性 computed property,其值是每次存取時計算出來的,像是物件中若有屬性 firstName 與 lastName,可以設置一個存取器屬性 fullName ,透過 setter 設定將 firstName 與 lastName 屬性相加印出。
❓ 我有疑問
其實可以在物件內建立一個方法就可以,為什麼要設置為 setter 呢?
根據忍者 2 的講解,若某個值只依賴自物件的內部狀態(如:firstName、lastName),比起以方法形式呈現,以屬性的方式做讀取其實更合理!
實際操作如下:
let aurther = {
firstName : 'Sherry',
lastName : 'Ho',
get fullName(){
consle.log(this.firstName + this.lastName)
},
set fullName(name){
let _name_ = name.split(' ')
this.firstName = _name_[0]
this.lastName = _name_[1]
}
}
aurther.fullName // SherryHo,呼叫 getter 取值
aurther.fullName = 'Sam Smith' // 重新指派值會呼叫 setter 將新值當參數傳入
aurther.firstName // Sam,變為 setter 新賦的值
aurther.fullName // Sam Smith
在 DevTools 印出可以看到屬於存取器屬性前會加上 setter 與 getter 字樣。
在 class
內加上 set 和 get 關鍵字,就可以定義存取器屬性。
// class 內寫法
class Name{
construcor(){}
set name(){}
get name(value){}
}
舉例:
定義一個 class 名稱為 Cake,設置一個可讀寫的屬性 producer,這個存取器屬性會存入 prototype 物件內,以 Cake 創建的實例可以透過原型鏈取得。
class Cake {
constructor(flavor){
this.flavor = flavor;
this._producer = 'Hoo'
}
set producer(name){
this._producer = name;
}
get producer(){
return this._producer;
}
}
let cake1 = new Cake('Tiramisu')
cake1.producer // Hoo,實例可透過原型鏈取得 producer 屬性
在 DevTools 中印出可以看到,存取器屬性 producer 存在於 prototype 內
透過 Object.defineProperty 可以定義或修改物件中的屬性。
Object.defineProperty(目標物件,'特性名稱', {setter, getter 描述})
let cake = {};
Object.defineProperty(cake, 'producer', {
get: function (){
return this.producer
},
set: function (name){
this.producer = name;
}
})
可以透過 Object.defineProperty 來控制存取私有變數,與物件實質和 class 不同的是,透過 Object.defineProperty 會和私有變數建立在相同的範圍中!
function Cake() {
let _cakeRating = 0;
Object.defineProperty(this, 'cakeRating', {
get: ()=>{
return _cakeRating;
},
set: (value)=>{
_cakeRating = value;
}
})
}
let cake1 = new Cake();
cake1.cakeRating = 10; // 透過 getter 指派值給 _cakeRating 變數
console.log( cake1.cakeRating ) // 10,只能透過 getter 取到 _cakeRating 這個私有變數
若對 getter 屬性重新賦值,在一般模式下不會產生效果,引擎會自動忽略這項動作,但在嚴格模式下禁止這項動作,會拋出錯誤提醒不能對唯讀屬性修改。
'use strict'
class Cake {
constructor(flavor){
this.flavor = flavor;
this._productionDate = 'Oct.3, 2021'
}
set productionDate(date){
this._productionDate = date;
}
get producer(){
return 'this.Hoo';
}}
let cake1 = new Cake('cream')
a.producer = 'sherry' // error! Cannot set property producer of #<Cake> which has only a getter
008重新認識 JavaScipt
忍者 JavaScript 開發技巧探秘第二版 by John Resig, Bear Bibeault, Josip Maras
MDN