該提案是對 class field declarations 提案中關於私有成員語法的補充,進一步為 class 引入了 private methods and accessors (getter/setters)。目前處於 Stage 3 階段。
與宣告私有私有成員一樣的是,私有方法和私有訪問器都使用 #
作為字首標識。
為了更好地說明該提案中它引入功能的使用場景。先以一個功能為例:
// 自定義元素:點選後,實現數值自增
class Counter extends HTMLElement {
#xValue = 0;
constructor() {
super();
this.onclick = this.clicked.bind(this);
}
get x() {
return this.#xValue;
}
set x(value) {
this.#xValue = value;
window.requestAnimationFrame(this.render.bind(this));
}
clicked() {
this.x++;
}
connectedCallback() {
this.render();
}
render() {
this.textContent = this.x.toString();
}
}
// 以 <num-counter> 標籤的形式註冊
window.customElements.define('num-counter', Counter);
這裡 xValue 被封裝成了私有成員,只供在內部訪問。按照提案中的解釋,這種方式帶來的好處是:
By declaring fields up-front, class definitions become more self-documenting; instances go through fewer state transitions, as declared fields are always present.
大致是說,提前宣告變數的方式,更直接自然。狀態初始化已在開頭完成,類中的邏輯程式碼會更加緊湊。
但這樣的程式碼還有最佳化的空間,我們希望這個自定義的元素的表現更接近於原生元件。
比如,這裡的訪問器屬性 x
,clicked
和 render
方法,應該只是元素內部的狀態,而不應該對外暴露給外面。因此,我們可以做出如下修改,以達到目的。
class Counter extends HTMLElement {
#xValue = 0;
constructor() {
super();
this.onclick = this.#clicked.bind(this);
}
get #x() {
return this.#xValue;
}
set #x(value) {
this.#xValue = value;
window.requestAnimationFrame(this.#render.bind(this));
}
#clicked() {
this.#x++;
}
connectedCallback() {
this.#render();
}
#render() {
this.textContent = this.#x.toString();
}
}
window.customElements.define('num-counter', Counter);
With all of its implementation kept internal to the class, this custom element can present an interface which is basically just like a built-in HTML element. Users of the custom element don’t have the power to mess around with any of its internals.
這樣一來,使用者怎麼著也不會誤操作 Counter 例項的內部方法了。
Tip:
需要額外注意的是,本提案引入的 private methods and accessors (getter/setters) 功能,僅是針對 class 的,不針對物件字面量。在物件字面量中使用會報錯。
(完)
本作品採用《CC 協議》,轉載必須註明作者和本文連結