国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 編程 > JavaScript > 正文

詳解ES6系列之私有變量的實(shí)現(xiàn)

2019-11-19 12:29:46
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

前言

在閱讀 《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()); // privateconsole.log(ex._private); // private

優(yōu)點(diǎn)

  • 寫法簡(jiǎn)單
  • 調(diào)試方便
  • 兼容性好

缺點(diǎn)

  • 外部可以訪問(wèn)和修改
  • 語(yǔ)言沒(méi)有配合的機(jī)制,如 for in 語(yǔ)句會(huì)將所有屬性枚舉出來(lái)
  • 命名沖突

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()); // privateconsole.log(ex._private); // undefined

優(yōu)點(diǎn)

  • 無(wú)命名沖突
  • 外部無(wú)法訪問(wèn)和修改

缺點(diǎn)

  • constructor 的邏輯變得復(fù)雜。構(gòu)造函數(shù)應(yīng)該只做對(duì)象初始化的事情,現(xiàn)在為了實(shí)現(xiàn)私有變量,必須包含部分方法的實(shí)現(xiàn),代碼組織上略不清晰。
  • 方法存在于實(shí)例,而非原型上,子類也無(wú)法使用 super 調(diào)用
  • 構(gòu)建增加一點(diǎn)點(diǎn)開(kāi)銷

實(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()); // privateconsole.log(ex._private); // undefined

優(yōu)點(diǎn)

  • 無(wú)命名沖突
  • 外部無(wú)法訪問(wèn)和修改

缺點(diǎn)

  • 寫法有一點(diǎn)復(fù)雜
  • 構(gòu)建增加一點(diǎn)點(diǎn)開(kāi)銷

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()); // privateconsole.log(ex.name); // undefined

優(yōu)點(diǎn)

  • 無(wú)命名沖突
  • 外部無(wú)法訪問(wèn)和修改
  • 無(wú)性能損失

缺點(diǎn)

  1. 寫法稍微復(fù)雜
  2. 兼容性也還好

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()); // privateconsole.log(ex.name); // undefined

如果這樣寫,你可能覺(jué)得封裝性不夠,你也可以這樣寫:

/** * 實(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()); // privateconsole.log(ex.name); // undefined

優(yōu)點(diǎn)

  • 無(wú)命名沖突
  • 外部無(wú)法訪問(wèn)和修改

缺點(diǎn)

  • 寫法比較麻煩
  • 兼容性有點(diǎn)問(wè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 字段呢?比如說(shuō)這樣:

class Foo { private value; equals(foo) {  return this.value === foo.value; }}

簡(jiǎn)單點(diǎn)來(lái)說(shuō),就是嫌麻煩,當(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)在其他語(yǔ)言,比如說(shuō) Java 和 C++ 中也是一樣的,類的成員函數(shù)中可以訪問(wèn)同類型實(shí)例的私有變量,這是因?yàn)樗接惺菫榱藢?shí)現(xiàn)“對(duì)外”的信息隱藏,在類自己內(nèi)部,沒(méi)有必要禁止私有變量的訪問(wèn),你也可以理解為私有變量的限制是以類為單位,而不是以對(duì)象為單位,此外這樣做也可以為使用者帶來(lái)便利。

既然獲取值是可以的,那么打印的結(jié)果應(yīng)該為 true,但是如果我們傳入的值不是 Foo 的實(shí)例,而是一個(gè)其他對(duì)象呢?

var foo1 = new Foo();console.log(foo1.equals({ value: 2}));

當(dāng)然這里代碼也是可以正常運(yùn)行的,但是對(duì)于編譯器來(lái)說(shuō),就有一點(diǎn)麻煩了,因?yàn)榫幾g器不知道 value 到底是 foo 的正常屬性還是私有屬性,所以編譯器需要做判斷,先判斷 foo 是不是 Foo 的實(shí)例,然后再接著獲取值。

這也意味著每次屬性訪問(wèn)都需要做這樣一個(gè)判斷,而引擎已經(jīng)圍繞屬性訪問(wèn)做了高度優(yōu)化,懶得改,而且還降低速度。

不過(guò)除了這個(gè)工作之外,還會(huì)有一些其他的內(nèi)容需要考慮,比如說(shuō):

  • 你必須將私有的 key 編碼進(jìn)每個(gè)詞法環(huán)境
  • for in 可以遍歷這些屬性嗎?
  • 私有屬性和正常屬性同名的時(shí)候,誰(shuí)會(huì)屏蔽誰(shuí)?
  • 怎么防止私有屬性的名稱不被探測(cè)出來(lái)。

關(guān)于使用 # 而不使用 private 更多的討論可以參考這個(gè)Issue

當(dāng)然這些問(wèn)題都可以被解決啦,就是麻煩了點(diǎn)。

而如果你選擇 #,實(shí)現(xiàn)的方式將跟 JavaScript 對(duì)象屬性完全沒(méi)有關(guān)系,將會(huì)使用 private slots 的方式以及使用一個(gè)新的 slot 查找語(yǔ)法,總之就是會(huì)比 private 的實(shí)現(xiàn)方式簡(jiǎn)單很多。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持武林網(wǎng)。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 古浪县| 那曲县| 怀集县| 蓬莱市| 竹北市| 广东省| 汾阳市| 石首市| 昌吉市| 屏东市| 清河县| 辽宁省| 黄陵县| 收藏| 通化县| 阜阳市| 保德县| 屏东县| 阳江市| 安福县| 保亭| 当涂县| 肃南| 鹰潭市| 田阳县| 繁峙县| 平顶山市| 天镇县| 淳安县| 侯马市| 丰宁| 东方市| 新安县| 罗江县| 潼关县| 手游| 文安县| 九龙坡区| 安溪县| 四川省| 旺苍县|