web-dev-qa-db-ja.com

Javascriptでのプライベートインスタンス変数の実装

どうしてこんなに長い間見逃してきたのかわかりません。私はプライベートインスタンス変数がこのように機能すると想定してきましたが、そうではありません。確かに、それらは(非グローバルのように)プライベートですが、変数はインスタンス間で共有されます。これは、いくつかの非常に紛らわしいバグにつながりました。

そこにあるいくつかの最高のライブラリによって実装されたベストプラクティスに従っていると思いましたが、何かを逃したようです。

var Printer = (function(){
    var _Word;

    Printer = function(Word){
        _Word = Word;
    }

    _print = function(){
        console.log(_Word);
    }

    Printer.prototype = {
        print: _print
    }
    return Printer;
})();

var a = new Printer("Alex");
var b = new Printer("Bob");

a.print(); //Prints Bob (!)
b.print(); //Prints Bob

この投稿を見てきましたが、プライベートインスタンス変数を実装するためのベストプラクティスについては説明していません。 (これは私が欲しいものの名前でもありますか?) JavaScriptのプライベート変数とインスタンス変数のメソッドと変数のスコープ

私もこの投稿を見ましたが、「this」キーワードの使用は私が以前行っていたものです。難読化されていないので、避けようとしていました。これは本当に唯一の方法ですか? プロトタイプ継承でのインスタンスメソッド/変数の実装

21
SimplGy

あなたはその閉鎖でいくつかの奇妙なことをしています。 _WordPrinter関数で宣言する必要があり、匿名閉鎖の土地では失われません。

function Printer(Word) {
    var _Word = Word;

    this.print = function () {
        console.log(_Word);
    }
}

var a = new Printer("Alex");
var b = new Printer("Bob");

a.print(); //Prints Alex
b.print(); //Prints Bob

これにより、すべてのprintインスタンスで新しいPrinter関数が作成される代わりに、_Wordがプライベートに保たれます。このコストを削減するには、_Wordを公開し、プロトタイプで単一のprint関数を使用します。

function Printer(Word) {
    this._Word = Word;
}

Printer.prototype.print = function () {
    console.log(this._Word);
}

var a = new Printer("Alex");
var b = new Printer("Bob");

a.print(); //Prints Alex
b.print(); //Prints Bob

本当に_Wordが公開されているかどうかは問題ですか?個人的には、特に_プレフィックスがあると、そうは思いません。

28
Matt Ball

プライベートは高価です。可能であれば避けてください

プライベートは存在しません。これをエミュレートするには、2つの方法のいずれかを実行できます。

  • 閉鎖
  • ウィークマップ

閉鎖

function makePrinter(Word) {
  return {
    print: function () {
      console.log(Word)
    }
  }
}

WeakMap

weakmaps のブラウザサポートはひどいです。おそらくエミュレーションが必要になるでしょう、私はお勧めします pd.Name

var Printer = (function () {
  var privates = function (obj) {
    var v = map.get(obj)
    if (v === undefined) {
      v = {}
      map.set(obj, v)
    } 
    return v
  }, map = new WeakMap()

  return {
    constructor: function (Word) {
      privates(this).Word = Word
    },
    print: function () {
      console.log(privates(this).Word)
    }
  }
}());

賢明なオブジェクト

var Printer = {
  constructor: function (Word) {
    this._Word = Word
  },
  print: function () {
    console.log(this._Word)
  }
}
13
Raynos

ES2015クラスを使用する意思がある場合(私はすでに答えました ここ ですが、便宜上繰り返します)、

eSNextでは、次のように Javascriptプライベート変数 を使用できます。

class Foo {
  #bar = '';
  constructor(val){
      this.#bar = val;
  }
  otherFn(){
      console.log(this.#bar);
  }
}

プライベートフィールド#barは、Fooクラスの外部からはアクセスできません。

1
Nitin Jadhav

thisを使用してコードを少し変更すると機能します。 Printer.prototype.printの正しいインスタンスがaオブジェクトに対してインスタンス化されていませんでした。

var Printer = (function(){
    var _Word;

    Printer = function(Word){
        this._Word = Word;
    }

    _print = function(){
        console.log(this._Word);
    }

    Printer.prototype = {
        print: _print
    }

    return Printer;
})();

var a = new Printer("Alex");
var b = new Printer("Bob");

a.print(); //Prints Alex
b.print(); //Prints Bob
0
nashcheez