在 Javascript 中实现私有实例变量

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9572029/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 07:05:31  来源:igfitidea点击:

Implementing private instance variables in Javascript

javascriptprivate-members

提问by SimplGy

I don't know how I've missed this for so long. I've been presuming private instance variables to work like this, but they don't. They're private (as in non-global), certainly, but the variables are shared across instances. This led to some very confusing bugs.

我不知道我怎么错过了这么久。我一直假设私有实例变量像这样工作,但他们没有。当然,它们是私有的(就像在非全局中一样),但是变量是跨实例共享的。这导致了一些非常令人困惑的错误。

I thought I was following the best practices implemented by some of the best libraries out there, but it seems I missed something.

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

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

I have looked at this post, but it doesn't describe a best practice for implementing private instance variables. (is this even the name of what I want?) Method and variable scoping of private and instance variables in JavaScript

我看过这篇文章,但它没有描述实现私有实例变量的最佳实践。(这甚至是我想要的名称吗?) JavaScript 中私有变量和实例变量的方法和变量范围

I also looked at this post, but the use of the 'this' keyword is what I used to do. Because it doesn't obfuscate I was trying to avoid it. Is this really the only way? Implementing instance methods/variables in prototypal inheritance

我也看过这篇文章,但我以前经常使用“this”关键字。因为它不会混淆我试图避免它。这真的是唯一的方法吗? 在原型继承中实现实例方法/变量

回答by Matt Ball

You're doing some wonky stuff with that closure. _wordneeds to be declared in the Printerfunction, not lost in anonymous-closure land:

你正在用那个闭包做一些奇怪的事情。_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

This keeps _wordprivate, at the expense of creating a new printfunction on every Printerinstance. To cut this cost, you expose _wordand use a single printfunction on the prototype:

这保持_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

Does it reallymatter that _wordis exposed? Personally, I don't think so, especially given the _prefix.

暴露了真的重要_word吗?就个人而言,我不这么认为,特别是考虑到_前缀。

回答by Raynos

Privates are expensive, avoid them if possible

私人是昂贵的,尽可能避免它们

Private doesn't exist. You can do one of two things to emulate this.

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

  • closures
  • Weakmaps
  • 关闭
  • 弱图

Closures

关闭

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

WeakMap

弱映射

Browser support for weakmapsis awful. You will probably need an emulation, I recommend pd.Name

浏览器对弱图的支持很糟糕。你可能需要一个模拟,我推荐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)
    }
  }
}());

Sensible objects

敏感对象

var Printer = {
  constructor: function (word) {
    this._word = word
  },
  print: function () {
    console.log(this._word)
  }
}

回答by Nitin Jadhav

If you are willing to use ES2015 classes (I already answered it here, but repeating for the sake of convenience),

如果你愿意使用 ES2015 类(我已经在这里回答,但为了方便重复),

with ESNext, you can use Javascript private variableslike this:

使用 ESNext,您可以像这样使用Javascript 私有变量

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

Private field #bar is not accessible outside Foo class.

私有字段 #bar 在 Foo 类之外不可访问。

回答by nashcheez

A slight modification to the code using thiswill work. The correct instance of Printer.prototype.printwas not being instantiated for the aobject.

对使用的代码稍作修改即可thisPrinter.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