您好,登錄后才能下訂單哦!
這期內(nèi)容當中小編將會給大家?guī)碛嘘P(guān)怎么在ES6中實現(xiàn)私有變量,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
1. 約定
實現(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ào)試方便
兼容性好
缺點
外部可以訪問和修改
語言沒有配合的機制,如 for in 語句會將所有屬性枚舉出來
命名沖突
2. 閉包
實現(xiàn)一
/** * 實現(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)點
無命名沖突
外部無法訪問和修改
缺點
constructor 的邏輯變得復雜。構(gòu)造函數(shù)應該只做對象初始化的事情,現(xiàn)在為了實現(xiàn)私有變量,必須包含部分方法的實現(xiàn),代碼組織上略不清晰。
方法存在于實例,而非原型上,子類也無法使用 super 調(diào)用
構(gòu)建增加一點點開銷
實現(xiàn)二
/** * 實現(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)點
無命名沖突
外部無法訪問和修改
缺點
寫法有一點復雜
構(gòu)建增加一點點開銷
3. Symbol
實現(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)點
無命名沖突
外部無法訪問和修改
無性能損失
缺點
寫法稍微復雜
兼容性也還好
4. WeakMap
實現(xiàn)
/** * 實現(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
如果這樣寫,你可能覺得封裝性不夠,你也可以這樣寫:
/** * 實現(xiàn)二 */ const Example = (function() { var _private = new WeakMap(); // 私有成員存儲容器 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)點
無命名沖突
外部無法訪問和修改
缺點
寫法比較麻煩
兼容性有點問題
有一定性能代價
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; } }
簡單點來說,就是嫌麻煩,當然也有性能上的考慮……
舉個例子,如果我們不使用 #,而是使用 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));
在這里我們新建了兩個實例,然后將 foo2 作為參數(shù)傳入了 foo1 的實例方法中。
那么我們可以獲取 foo2.value 的值嗎?如果我們直接 foo2.value
肯定是獲取不到值的,畢竟是私有變量,可是 equals 是 Foo 的一個類方法,那么可以獲取到的嗎?
答案是可以的。
其實這點在其他語言,比如說 Java 和 C++ 中也是一樣的,類的成員函數(shù)中可以訪問同類型實例的私有變量,這是因為私有是為了實現(xiàn)“對外”的信息隱藏,在類自己內(nèi)部,沒有必要禁止私有變量的訪問,你也可以理解為私有變量的限制是以類為單位,而不是以對象為單位,此外這樣做也可以為使用者帶來便利。
既然獲取值是可以的,那么打印的結(jié)果應該為 true,但是如果我們傳入的值不是 Foo 的實例,而是一個其他對象呢?
var foo1 = new Foo(); console.log(foo1.equals({ value: 2 }));
當然這里代碼也是可以正常運行的,但是對于編譯器來說,就有一點麻煩了,因為編譯器不知道 value 到底是 foo 的正常屬性還是私有屬性,所以編譯器需要做判斷,先判斷 foo 是不是 Foo 的實例,然后再接著獲取值。
這也意味著每次屬性訪問都需要做這樣一個判斷,而引擎已經(jīng)圍繞屬性訪問做了高度優(yōu)化,懶得改,而且還降低速度。
不過除了這個工作之外,還會有一些其他的內(nèi)容需要考慮,比如說:
你必須將私有的 key 編碼進每個詞法環(huán)境
for in 可以遍歷這些屬性嗎?
私有屬性和正常屬性同名的時候,誰會屏蔽誰?
怎么防止私有屬性的名稱不被探測出來。
關(guān)于使用 # 而不使用 private 更多的討論可以參考這個Issue。
當然這些問題都可以被解決啦,就是麻煩了點。
而如果你選擇 #,實現(xiàn)的方式將跟 JavaScript 對象屬性完全沒有關(guān)系,將會使用 private slots 的方式以及使用一個新的 slot 查找語法,總之就是會比 private 的實現(xiàn)方式簡單很多。
上述就是小編為大家分享的怎么在ES6中實現(xiàn)私有變量了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。