iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 11
0
Modern Web

從零開始進入 JavaScript & TypeScript 的世界系列 第 11

第11天-一樣優雅的屬性(Property)

  • 分享至 

  • xImage
  •  

在使用優雅的建構子存取修飾符(Constructor Access Modifiers)之後,我們可能會發現:如果我用 private 的話不就不能存取那個 member variable 了嗎?或許有人又會說:『加個 getset 就好了啊。』恩,我相信會這麼說的人之前應該有很高的機率是寫 Java 的。

那我們就先來看看,如果我們想要存取 member variable 最簡單的方式(就是不要增加 method啦)可以怎麼做:

class Rectangele {
    constructor(private width?: number, private length?: number) { }

    showWidthAndLength(): void {
        console.log('width is ' + this.width, 'length is ' + this.length);
    }
}

let rectangle1 = new Rectangele(10, 20);
rectangle1.showWidthAndLength();

以上面的程式碼來說,如果我們想要存取 widthlength, 單純使用 rectangle1.widthrectangle.length 肯定會出錯,因為 widthlength 目前都是屬於 private 私有層級的。

那如果將 private 改成 public 呢?

constructor(private width?: number, private length?: number) { }

如果改成上述那樣,我們就可以用 rectangle1.width = 某個數字 (length 亦同) 這種方式直接來存取了。可是,又有另一個問題,假設我們想要限制 widthlength 都必須要是大於零得正整數呢?

這時候就一定要增加 setget 函式了。下面是增加函式後的結果:

class Rectangele {
    constructor(private width?: number, private length?: number) { }

    showWidthAndLength(): void {
        console.log('width is ' + this.width, 'length is ' + this.length);
    }

    setWidth(width: number): void {
        if (width <= 0) {
            throw new Error("value cannot be less or equal to 0.")
        }
        this.width = width;
    }
    getWidth(): number {
        return this.width;
    }

    setLength(length: number) {
        if (length <= 0) {
            throw new Error("value cannot be less or equal to 0.")
        }
        this.length = length;
    }

    getLength(): number {
        return this.length;
    }
}

這樣一來就可以達到我們在改變 widthlength 的內容時,如果他小於或等於 0, 我們就可以丟出一個錯誤來達到防護的目的。不過,這樣做又產生了另一個問題,也就是我們在取直或給值的時候會變成下面這樣做:

let rect = new Rectangle(10, 20);
// 取得 width 的值
let width = rect.getWidth();
// 設定 width
rect.setLength(1111);

有發現嗎?有別於先前用 public 的做法,這次我們改用兩個不同的函式去取值以及設定值。那這樣程式寫起來不就又不優雅了,優雅只做了一半。因次,今天的主題就要登場了 -- Property (屬性)

我們只要使用屬性,就可以解決這個問題。他的語法就是使用 set VARIABLE_NAME 以及 get VARIABLE_NAME, 直接來看範例:

class Rectangele {
    constructor(private _width?: number, private _length?: number) { }

    showWidthAndLength(): void {
        console.log('width is ' + this.width, 'length is ' + this.length);
    }

    set width(value: number) { // 請注意getter 或 setter 是不能寫回傳型別的,否則會出錯。
        if (value <= 0) {
            throw new Error("value cannot be 0 or less than 0.")
        }
        this.width = value;
    }

    get width() {
        return this._width;
    }

    set length(value: number) {
        if (value <= 0) {
            throw new Error("value cannot be 0 or less than 0.")
        }
        this._length = value;
    }

    get length() {
        return this._length;
    }
}

這樣我們就可以用原本很優雅的方式來給值或取值了。就像下面這樣:

Rectangle rect = new Rectangle(1, 2);
rect.width = 101;
let width = rect.width;

最後,如果你有注意到的話,你會發現在建構子的部分,我把

constructor(private width?: number, private length?: number) { }

改成

constructor(private _width?: number, private _length?: number) { }

其實這個目的就是要 settergetter 的名字不要和建構子裡面的變數名稱,也就是會變成 member variable 的名稱相衝突,所以我們就在建構子的參數前面都加了個底線。


上一篇
第10天-優雅的建構子存取修飾符
下一篇
第12天-const 與 readonly
系列文
從零開始進入 JavaScript & TypeScript 的世界30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言