首頁  >  文章  >  web前端  >  ES6中私有變數的實作總結(程式碼範例)

ES6中私有變數的實作總結(程式碼範例)

不言
不言轉載
2018-11-21 11:25:491668瀏覽

這篇文章帶給大家的內容是關於ES6中私有變數的實作總結(程式碼範例),有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

在閱讀 《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

優點

  1. #寫法簡單

  2. 調試方便

  3. 相容性好

缺點

  1. 外部可以存取和修改

  2. 語言沒有配合的機制,如for in 語句會將所有屬性枚舉出來

  3. 命名衝突

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

優點

  1. #無命名衝突

  2. ##外部無法存取和修改

缺點

  1. constructor 的邏輯變得複雜。建構函數應該只做物件初始化的事情,現在為了實現私有變量,必須包含部分方法的實現,程式碼組織上略不清晰。

  2. 方法存在於實例,而非原型上,子類別也無法使用super 呼叫

  3. 建構增加一點點開銷

實作二

/**
 * 实现二
 */
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

優點

  1. #無命名衝突

  2. ##外無法存取和修改
  3. 缺點

    寫法有一點複雜
  1. 建構增加一點點開銷
  2. 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

優點

    #無命名衝突
  1. 外部無法存取和修改
  2. 無效能損失

    #寫法稍微複雜
  1. 相容性也還好
  2. 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

優點

    無命名衝突
  1. ##外部無法存取和修改
  2. 缺點

寫法比較麻煩
  1. ##相容性有點問題

  2. 有一定效能代價

  3. 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;
      }
    }
  4. 那麼為什麼不直接使用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 編碼進每個詞法環境

  1. for in 可以遍歷這些屬性嗎?

  2. 私有屬性和正常屬性同名的時候,誰會封鎖誰?

  3. 怎麼防止私有屬性的名稱不被偵測出來。

  4. 關於使用 # 而不使用 private 更多的討論可以參考這個 Issue。

  5. 當然這些問題都可以解決啦,就是麻煩了點。

而如果你選擇#,實作的方式將跟JavaScript 物件屬性完全沒有關係,將會使用

private slots

的方式以及使用一個新的slot 尋找語法,總之就是會比private 的實作方式簡單很多。

#

以上是ES6中私有變數的實作總結(程式碼範例)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:segmentfault.com。如有侵權,請聯絡admin@php.cn刪除