在Javascript中实现私有实例变量

时间:2012-03-05 18:39:43

标签: javascript private-members

我不知道我多久都错过了这个。我一直假设私有实例变量像这样工作,但他们没有。当然,它们是私有的(如非全局的),但变量是跨实例共享的。这导致了一些非常混乱的错误。

我以为我正在遵循一些最好的图书馆实施的最佳做法,但似乎我错过了一些东西。

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

我看过这篇文章,但没有描述实现私有实例变量的最佳实践。 (这甚至是我想要的名字吗?) Method and variable scoping of private and instance variables in JavaScript

我也查看了这篇文章,但使用'this'关键字是我以前做的。因为它没有混淆我试图避免它。这真的是唯一的方法吗? Implementing instance methods/variables in prototypal inheritance

4 个答案:

答案 0 :(得分:28)

你正在做那些关闭的好东西。 _word需要在Printer函数中声明,而不是在匿名封闭的土地上丢失:

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

这会使_word保密,但会牺牲在每个print实例上创建新的Printer函数。要降低此费用,您需要公开_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前缀。

答案 1 :(得分:13)

Privates are expensive, avoid them if possible

私人不存在。你可以做两件事之一来模仿这个。

  • Weakmaps

闭包

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)
  }
}

答案 2 :(得分:0)

使用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

答案 3 :(得分:0)

如果您愿意使用ES2015类(我已经here回答过,但是为了方便起见重复),

通过ESNext,您可以像这样使用Javascript private variables

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

在Foo类之外无法访问私有字段#bar。