0%

JS核心-(55)-物件屬性延伸章節:屬性的特徵-Getter 與 Setter,賦值運算不使用函式

前言

如何利用 Getter 與 Setter 來進行物件屬性的賦值


var wallet = {
    total: 100
};

假設錢包裡面的總金額有 100 元,我們要修改裡面的錢,通常會使用

wallet.total = 300;

console.log(wallet.total);

印出來後

這樣子的作法,我們是直接把值覆蓋過原本的值,但有時候我們會需要根據原本的值進行一些運算,

這種狀況就非常適合使用 GetterSetter

  • Getter: 取得特定值的方法
  • Setter: 存特定值的方法

以上面的例子為基礎,用 Setter 設定存 total 的屬性


Setter 存特定值的方法

var wallet = {
    total: 100,
    set save (price) {
        this.total += price / 2;
    }
};

wallet.save = 300;

console.log(wallet.total);

我們先在 wallet 的屬性中新增了下面這段

set save (price) {
    this.total += price / 2;
}

可以看到利用 set 作為字首,接上自定義名稱 save ,再加上( ) { },有點類似傳統函式,但少了 function 的開頭宣

告,之後也是將要進行運算的程式撰寫在大括號 { } 內,就算定義完成。

實際上的呼叫和傳統函式的呼叫不太一樣,是透過

wallet.save = 300;

這樣的方式,如果有參數的話,則利用 = 要帶入的參數傳入,所以這邊的寫法如上面所示,

而結果就可以看到是運算過後的250


Getter 取得特定值的方法

其實 GetterSetter 差不多,只是差別在於最後要 return 你取到的值,並且不會有傳入的參數。

var wallet = {
    total: 100,
    set save (price) {
        this.total += price / 2;
    },
    get save () {
        return this.total;
    }
};

一樣的方式 ~ 用逗號 , 隔開之後,使用關鍵字 get 加上自定義名稱 save ,再加上 ( ) { }

那麼執行的話,只需要使用表達式即可,wallet.save

var wallet = {
    total: 100,
    set save (price) {
        this.total += price / 2;
    },
    get save () {
        return this.total;
    }
};

wallet.save = 300;

console.log(wallet.total);
console.log(wallet.save);

接著來看看 wallet 這個物件變成怎麼樣

可以看到 totalgettersetter還有一個 save: (...) 這個是 getter,但還沒有取值的狀態,如果我們點下去之後,才會從點下去的當下去資料中取這個值

稍微把程式碼改動一下讓大家比較能夠了解

var wallet = {
    total: 100,
    set save (price) {
        this.total += price / 2;
    },
    get save () {
        return this.total;
    }
};

console.log(wallet.save, wallet);

wallet.save = 300;

// console.log(wallet.total);
// console.log(wallet.save);

可以看到我故意把 console.log(wallet.save, wallet); 放在 setter 執行之前,這樣取到的值一定是 100

但是這時候物件裡面的 save: (...) 我還沒按,按了之後就呈現

也就是說,按下去的當下,js 的程式碼都全部跑完了,才去取得處理完的資料狀態,也就是 250


利用 Object.defineProperty( ) 定義 Getter 以及 Setter

var wallet = {
    total: 100
};

Object.defineProperty(wallet, 'save', {
    set: function (price) {
        this.total += price / 2;
    },
    get: function () {
        return this.total;
    }
});

console.log(wallet.save, wallet);

wallet.save = 300;

如同之前的寫法所示,功能一樣可以照常運作,只是眼尖的人可能會發現 save: (...) 的屬性顏色跟之前的不一樣,變成淡紫

色,如果還對上一篇文章有印象的人就會知道,這代表 enumerable 的狀態是 false

所以我們就來看看 Getter 以及 Setter 現在的狀態:

console.log('Getter and Setter', Object.getOwnPropertyDescriptor(wallet, 'save'));

果然,configurable 以及 enumerable 都是 false

那麼如果我們今天要把它改成 true 的話也很簡單,只需要 Object.defineProperty 中進行調整就可以了

Object.defineProperty(wallet, 'save', {
    configurable:true,
    enumerable: true,
    set: function (price) {
        this.total += price / 2;
    },
    get: function () {
        return this.total;
    }
});

console.log('Getter and Setter', Object.getOwnPropertyDescriptor(wallet, 'save'));


實戰練習

Q: 需要取得陣列中的第一個值以及最後一個值

A:

var a = ['1', '2', '3'];

Object.defineProperties(Array.prototype, {
    getFirst: {
        get: function () {
            return this[0];
        }
    },
    getLast: {
        get: function () {
            return this[this.length - 1];
        }
    }
});

console.log('getFirst', a.getFirst);
console.log('getLast', a.getLast);