摘要:前言在閱讀入門的時候,零散的看到有私有變量的實現,所以在此總結一篇。構造函數應該只做對象初始化的事情,現在為了實現私有變量,必須包含部分方法的實現,代碼組織上略不清晰。
前言
在閱讀 《ECMAScript 6 入門》的時候,零散的看到有私有變量的實現,所以在此總結一篇。
1. 約定 實現class Example { constructor() { this._private = "private"; } getName() { return this._private } } var ex = new Example(); console.log(ex.getName()); // private console.log(ex._private); // private優點
寫法簡單
調試方便
兼容性好
缺點外部可以訪問和修改
語言沒有配合的機制,如 for in 語句會將所有屬性枚舉出來
命名沖突
2. 閉包 實現一/** * 實現一 */ 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優點
無命名沖突
外部無法訪問和修改
缺點constructor 的邏輯變得復雜。構造函數應該只做對象初始化的事情,現在為了實現私有變量,必須包含部分方法的實現,代碼組織上略不清晰。
方法存在于實例,而非原型上,子類也無法使用 super 調用
構建增加一點點開銷
實現二/** * 實現二 */ 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優點
無命名沖突
外部無法訪問和修改
缺點寫法有一點復雜
構建增加一點點開銷
3. Symbol 實現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優點
無命名沖突
外部無法訪問和修改
無性能損失
缺點寫法稍微復雜
兼容性也還好
4. WeakMap 實現/** * 實現一 */ 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
如果這樣寫,你可能覺得封裝性不夠,你也可以這樣寫:
/** * 實現二 */ 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優點
無命名沖突
外部無法訪問和修改
缺點寫法比較麻煩
兼容性有點問題
有一定性能代價
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 關鍵字:
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 作為參數傳入了 foo1 的實例方法中。
那么我們可以獲取 foo2.value 的值嗎?如果我們直接 foo2.value 肯定是獲取不到值的,畢竟是私有變量,可是 equals 是 Foo 的一個類方法,那么可以獲取到的嗎?
答案是可以的。
其實這點在其他語言,比如說 Java 和 C++ 中也是一樣的,類的成員函數中可以訪問同類型實例的私有變量,這是因為私有是為了實現“對外”的信息隱藏,在類自己內部,沒有必要禁止私有變量的訪問,你也可以理解為私有變量的限制是以類為單位,而不是以對象為單位,此外這樣做也可以為使用者帶來便利。
既然獲取值是可以的,那么打印的結果應該為 true,但是如果我們傳入的值不是 Foo 的實例,而是一個其他對象呢?
var foo1 = new Foo(); console.log(foo1.equals({ value: 2 }));
當然這里代碼也是可以正常運行的,但是對于編譯器來說,就有一點麻煩了,因為編譯器不知道 value 到底是 foo 的正常屬性還是私有屬性,所以編譯器需要做判斷,先判斷 foo 是不是 Foo 的實例,然后再接著獲取值。
這也意味著每次屬性訪問都需要做這樣一個判斷,而引擎已經圍繞屬性訪問做了高度優化,懶得改,而且還降低速度。
不過除了這個工作之外,還會有一些其他的內容需要考慮,比如說:
你必須將私有的 key 編碼進每個詞法環境
for in 可以遍歷這些屬性嗎?
私有屬性和正常屬性同名的時候,誰會屏蔽誰?
怎么防止私有屬性的名稱不被探測出來。
關于使用 # 而不使用 private 更多的討論可以參考這個 Issue。
當然這些問題都可以被解決啦,就是麻煩了點。
而如果你選擇 #,實現的方式將跟 JavaScript 對象屬性完全沒有關系,將會使用 private slots 的方式以及使用一個新的 slot 查找語法,總之就是會比 private 的實現方式簡單很多。
參考《編程語言如何演化——以JS的private為例》賀師俊
Exploring ES6
譯 JS 新語法:私有屬性
ES6 系列ES6 系列目錄地址:https://github.com/mqyqingfeng/Blog
ES6 系列預計寫二十篇左右,旨在加深 ES6 部分知識點的理解,重點講解塊級作用域、標簽模板、箭頭函數、Symbol、Set、Map 以及 Promise 的模擬實現、模塊加載方案、異步處理等內容。
如果有錯誤或者不嚴謹的地方,請務必給予指正,十分感謝。如果喜歡或者有所啟發,歡迎 star,對作者也是一種鼓勵。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/108767.html
摘要:一個對象若只被弱引用所引用,則被認為是不可訪問或弱可訪問的,并因此可能在任何時刻被回收。也就是說,一旦不再需要,里面的鍵名對象和所對應的鍵值對會自動消失,不用手動刪除引用。如果有錯誤或者不嚴謹的地方,請務必給予指正,十分感謝。 前言 我們先從 WeakMap 的特性說起,然后聊聊 WeakMap 的一些應用場景。 特性 1. WeakMap 只接受對象作為鍵名 const map = ...
摘要:例如我們導入模塊,可以這么導入桃翁歡迎關注公眾號前端桃園報錯不能定義相同名字變量報錯,不能重新賦值小豬可以看到導入綁定這里不理解綁定,文章后面會解釋時,形式類似于對象解構,但實際上并無關聯。 歡迎訪問個人站點 簡介 何為模塊 一個模塊只不過是一個寫在文件中的 JavaScript 代碼塊。 模塊中的函數或變量不可用,除非模塊文件導出它們。 簡單地說,這些模塊可以幫助你在你的模塊中編寫...
摘要:前言這里的泛指之后的新語法這里的完全是指本文會不斷更新這里的使用是指本文會展示很多的使用場景這里的手冊是指你可以參照本文將項目更多的重構為語法此外還要注意這里不一定就是正式進入規范的語法。 前言 這里的 ES6 泛指 ES5 之后的新語法 這里的 完全 是指本文會不斷更新 這里的 使用 是指本文會展示很多 ES6 的使用場景 這里的 手冊 是指你可以參照本文將項目更多的重構為 ES6...
摘要:掛機科了次使用這個結構,匿名函數就有了自己的執行環境或閉包,然后我們立即執行。注意,匿名函數的圓括號是必需的,因為以關鍵字開頭的語句通常被認為是函數聲明請記住,中不能使用未命名的函數聲明。 這是專門探索 JavaScript 及其所構建的組件的系列文章的第 20 篇。 想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等著你! 如果你錯過了前面的章節,可以在這里找到它們: ...
閱讀 766·2023-04-25 17:33
閱讀 3626·2021-07-29 14:49
閱讀 2480·2019-08-30 15:53
閱讀 3434·2019-08-29 16:27
閱讀 2000·2019-08-29 16:11
閱讀 1030·2019-08-29 14:17
閱讀 2432·2019-08-29 13:47
閱讀 2016·2019-08-29 13:28