點燈坊

失くすものさえない今が強くなるチャンスよ

ECMAScript 之 Getter Property

Sam Xiao's Avatar 2020-01-12

Getter Property 讓我們可兼具 Function 的靈活與 Property 的方便,且其 Lazy 特性在一些需要 CPU 運算場合可延遲執行增進效率。

Version

macOS Catalina 10.15.2
VS Code 1.41.1
Quokka 1.0.267
ECMAScript 2015

Getter Function

let book = {
  data: [
    { title: 'FP in JavaScript', price: 100 }
  ],
  getTitle: function() {
    return this.data[0].title
  },
  setTitle: function(v) {
    this.data[0].title = v
  }
}

book.setTitle('Speaking JavaScript')
book.getTitle() // ?

Object 若想提供 property,卻又想如 function 般有彈性,過去只能透過 function 提供 getter 與 setter。

但也由於是 function,因此使用上並不如 property 直覺。

getter000

Getter Property

let book = {
  data: [
    { title: 'FP in JavaScript', price: 100 }
  ],
  get title() {
    return this.data[0].title
  },
  set title(v) {
    this.data[0].title = v
  }
}

book.title = 'Speaking JavaScript'
book.title // ?

ECMAScript 另外提供了 getter / setter property,只要在 function 前面加上 getset,就可得到 function 的彈性與 property 的直覺。

getter001

Computed Property Names

let book = {
  data: [
    { title: 'FP in JavaScript', price: 100 }
  ],
  get ['title']() {
    return this.data[0].title
  },
  set ['title'](v) {
    this.data[0].title = v
  }
}

book.title = 'Speaking JavaScript'
book.title // ?

ES6 支援了 computed property name,也能用在 getter property。

getter002

Class

class Book {
  constructor() {
    this.data = [
      { title: 'FP in JavaScript', price: 100 }
    ]
  }

  get title() {
    return this.data[0].title
  }

  set title(v) {
    this.data[0].title = v
  }
}

let book = new Book
book.title = 'Speaking JavaScript'
book.title // ?

ES6 的 class 也能使用 getter / setter property。

getter003

Object.defineProperty()

let book = {
  data: [
    { title: 'FP in JavaScript', price: 100 }
  ]
}

Object.defineProperty(book, 'title', {
  get: function() { return this.data[0].title },
  set: function(v) { this.data[0].title = v }
})

book.title = 'Speaking JavaScript'
book.title // ?

Getter property 只能在 object 或 class 事先定義,若想在 object 建立後才動態新增 getter property,就要改用 Object.defineProperty()

getter004

Summary

class Book {
  constructor() {
    this.data = [
      { title: 'FP in JavaScript', price: 100 }
    ]
  }

  get title() {
    return this.data[0].title
  }

  set title(v) {
    this.data[0].title = v
  }
}

let book = new Book

Object.defineProperty(book, 'price', {
  get: function() { return this.data[0].price },
  set: function(v) { this.data[0].price = v }
})

book.hasOwnProperty('title') // ?
book.hasOwnProperty('price') // ?

Getter property 與 Object.defineProperty() 若用在 object 則等效,但若用於 class 時則不太一樣。

Class 的 getter property 會建立在 object 的 prototype 上,但 Object.defineProperty() 則直接建立在 object 上,可使用 hasOwnProperty() 證明。

getter005

Lazy Getter

Getter Property 與傳統 Property 用起來感覺一樣,但何時該使用呢 ? MDN 提供了以下幾點建議:

  • 當 property 非常耗 CPU 時,使用 getter property 讓 property 延後到要使用才產生
  • 該 property 很少使用,可考慮要使用時再產生即可
  • 該 property 經常使用,可考慮 cache 下來,只有 getter property 第一次需正常運算,之後都使用 cache 版本

Conclusion

  • Getter property 讓我們同時擁有 function 的靈活又兼具 property 的方便
  • 當使用 object 時,getter property 與 Object.defineProperty() 等效;但當使用 class 時,兩者則不太一樣,getter property 會建立在 prototype 上,而 Object.defineProperty() 則直接建立在 object 內
  • Getter property 具有 lazy 特性,可在適當場合加以使用

Reference

許國政, 008 天重新認識 JavaScript
MDN, Getter