詳解ES6系列之私有變量的實(shí)現(xiàn)
前言
在閱讀 《ECMAScript 6 入門》的時(shí)候,零散的看到有私有變量的實(shí)現(xiàn),所以在此總結(jié)一篇。
1. 約定
實(shí)現(xiàn)
class Example {
constructor() {
this._private = 'private';
}
getName() {
return this._private
}
}
var ex = new Example();
console.log(ex.getName()); // private
console.log(ex._private); // private
優(yōu)點(diǎn)
- 寫法簡(jiǎn)單
- 調(diào)試方便
- 兼容性好
缺點(diǎn)
- 外部可以訪問和修改
- 語言沒有配合的機(jī)制,如 for in 語句會(huì)將所有屬性枚舉出來
- 命名沖突
2. 閉包
實(shí)現(xiàn)一
/**
* 實(shí)現(xiàn)一
*/
class Example {
constructor() {
var _private = '';
_private = 'private';
this.getName = function() {return _private}
}
}
var ex = new Example();
console.log(ex.getName()); // private
console.log(ex._private); // undefined
優(yōu)點(diǎn)
- 無命名沖突
- 外部無法訪問和修改
缺點(diǎn)
- constructor 的邏輯變得復(fù)雜。構(gòu)造函數(shù)應(yīng)該只做對(duì)象初始化的事情,現(xiàn)在為了實(shí)現(xiàn)私有變量,必須包含部分方法的實(shí)現(xiàn),代碼組織上略不清晰。
- 方法存在于實(shí)例,而非原型上,子類也無法使用 super 調(diào)用
- 構(gòu)建增加一點(diǎn)點(diǎn)開銷
實(shí)現(xiàn)二
/**
* 實(shí)現(xiàn)二
*/
const Example = (function() {
var _private = '';
class Example {
constructor() {
_private = 'private';
}
getName() {
return _private;
}
}
return Example;
})();
var ex = new Example();
console.log(ex.getName()); // private
console.log(ex._private); // undefined
優(yōu)點(diǎn)
- 無命名沖突
- 外部無法訪問和修改
缺點(diǎn)
- 寫法有一點(diǎn)復(fù)雜
- 構(gòu)建增加一點(diǎn)點(diǎn)開銷
3. Symbol
實(shí)現(xiàn)
const Example = (function() {
var _private = Symbol('private');
class Example {
constructor() {
this[_private] = 'private';
}
getName() {
return this[_private];
}
}
return Example;
})();
var ex = new Example();
console.log(ex.getName()); // private
console.log(ex.name); // undefined
優(yōu)點(diǎn)
- 無命名沖突
- 外部無法訪問和修改
- 無性能損失
缺點(diǎn)
- 寫法稍微復(fù)雜
- 兼容性也還好
4. WeakMap
實(shí)現(xiàn)
/**
* 實(shí)現(xiàn)一
*/
const _private = new WeakMap();
class Example {
constructor() {
_private.set(this, 'private');
}
getName() {
return _private.get(this);
}
}
var ex = new Example();
console.log(ex.getName()); // private
console.log(ex.name); // undefined
如果這樣寫,你可能覺得封裝性不夠,你也可以這樣寫:
/**
* 實(shí)現(xiàn)二
*/
const Example = (function() {
var _private = new WeakMap(); // 私有成員存儲(chǔ)容器
class Example {
constructor() {
_private.set(this, 'private');
}
getName() {
return _private.get(this);
}
}
return Example;
})();
var ex = new Example();
console.log(ex.getName()); // private
console.log(ex.name); // undefined
優(yōu)點(diǎn)
- 無命名沖突
- 外部無法訪問和修改
缺點(diǎn)
- 寫法比較麻煩
- 兼容性有點(diǎn)問題
- 有一定性能代價(jià)
5. 最新提案
class Point {
#x;
#y;
constructor(x, y) {
this.#x = x;
this.#y = y;
}
equals(point) {
return this.#x === point.#x && this.#y === point.#y;
}
}
那么為什么不直接使用 private 字段呢?比如說這樣:
class Foo {
private value;
equals(foo) {
return this.value === foo.value;
}
}
簡(jiǎn)單點(diǎn)來說,就是嫌麻煩,當(dāng)然也有性能上的考慮……
舉個(gè)例子,如果我們不使用 #,而是使用 private 關(guān)鍵字:
class Foo {
private value = '1';
equals(foo) {
return this.value === foo.value;
}
}
var foo1 = new Foo();
var foo2 = new Foo();
console.log(foo1.equals(foo2));
在這里我們新建了兩個(gè)實(shí)例,然后將 foo2 作為參數(shù)傳入了 foo1 的實(shí)例方法中。
那么我們可以獲取 foo2.value 的值嗎?如果我們直接 foo2.value 肯定是獲取不到值的,畢竟是私有變量,可是 equals 是 Foo 的一個(gè)類方法,那么可以獲取到的嗎?
答案是可以的。
其實(shí)這點(diǎn)在其他語言,比如說 Java 和 C++ 中也是一樣的,類的成員函數(shù)中可以訪問同類型實(shí)例的私有變量,這是因?yàn)樗接惺菫榱藢?shí)現(xiàn)“對(duì)外”的信息隱藏,在類自己內(nèi)部,沒有必要禁止私有變量的訪問,你也可以理解為私有變量的限制是以類為單位,而不是以對(duì)象為單位,此外這樣做也可以為使用者帶來便利。
既然獲取值是可以的,那么打印的結(jié)果應(yīng)該為 true,但是如果我們傳入的值不是 Foo 的實(shí)例,而是一個(gè)其他對(duì)象呢?
var foo1 = new Foo();
console.log(foo1.equals({
value: 2
}));
當(dāng)然這里代碼也是可以正常運(yùn)行的,但是對(duì)于編譯器來說,就有一點(diǎn)麻煩了,因?yàn)榫幾g器不知道 value 到底是 foo 的正常屬性還是私有屬性,所以編譯器需要做判斷,先判斷 foo 是不是 Foo 的實(shí)例,然后再接著獲取值。
這也意味著每次屬性訪問都需要做這樣一個(gè)判斷,而引擎已經(jīng)圍繞屬性訪問做了高度優(yōu)化,懶得改,而且還降低速度。
不過除了這個(gè)工作之外,還會(huì)有一些其他的內(nèi)容需要考慮,比如說:
- 你必須將私有的 key 編碼進(jìn)每個(gè)詞法環(huán)境
- for in 可以遍歷這些屬性嗎?
- 私有屬性和正常屬性同名的時(shí)候,誰會(huì)屏蔽誰?
- 怎么防止私有屬性的名稱不被探測(cè)出來。
關(guān)于使用 # 而不使用 private 更多的討論可以參考這個(gè)Issue。
當(dāng)然這些問題都可以被解決啦,就是麻煩了點(diǎn)。
而如果你選擇 #,實(shí)現(xiàn)的方式將跟 JavaScript 對(duì)象屬性完全沒有關(guān)系,將會(huì)使用 private slots 的方式以及使用一個(gè)新的 slot 查找語法,總之就是會(huì)比 private 的實(shí)現(xiàn)方式簡(jiǎn)單很多。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
html的DOM中document對(duì)象images集合用法實(shí)例
這篇文章主要介紹了html的DOM中document對(duì)象images集合用法,實(shí)例分析了images集合的語法與使用技巧,需要的朋友可以參考下2015-01-01
詳解weex默認(rèn)webpack.config.js改造
本篇文章主要介紹了詳解weex默認(rèn)webpack.config.js改造,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-01-01
document.styleSheets[0].rules 與 cssRules區(qū)別
document.styleSheets[0].rules 與 cssRules區(qū)別...2007-08-08

