【问题标题】:Private members in Javascript. Can they be non-static?Javascript 中的私有成员。它们可以是非静态的吗?
【发布时间】:2012-04-21 04:46:21
【问题描述】:

我这里有这段代码:

var Person = (function() {
    var name;

    var PersonConstructor = function(n) {
        name = n;
    };

    PersonConstructor.prototype.getName = function() {
        return name;
    };

    return PersonConstructor;

})();

var people = [];
var person1 = new Person("Foo");
var person2 = new Person("Bar");
alert(person1.getName()); // I want it to be Foo
people.push(person1);
people.push(person2);

我从here. 得到了模拟类的想法。但是当然,我忽略了私有变量var name;也是一个静态变量的事实。由于这阻碍了我目前的努力,我想知道是否有办法在这个例子中保持私人行为但避免静态行为?

【问题讨论】:

  • 你不能让原型函数在构造函数中引用局部变量。我会远离在 JavaScript 中模拟可见性的方法。这不是语言的一部分,并且产生的问题多于它的帮助。使用适当的文档,将属性标记为 @private,并根据代码的用例,使用 Google 的 Closure 编译器之类的工具仅通过其实际名称公开公共属性。

标签: javascript static private encapsulation members


【解决方案1】:

使用this

var Person = (function() {
  var PersonConstructor = function(n) {
    this.name = n;
  };

  PersonConstructor.prototype.getName = function() {
    return this.name;
  };

  return PersonConstructor;    
})();

很遗憾,这不会保留私有状态。

【讨论】:

  • 这不保留名称的“私有”状态?
  • 这确实有效,但如上所述它不保留所谓的私有状态,也许我应该坚持命名约定。
【解决方案2】:

这只是范围问题。

var Person = (function(){

    var PersonConstructor = function(n){ 
        // *************************************************************** 
        // PRIVATE VARIABLES AND FUNCTIONS 
        // ONLY PRIVELEGED METHODS MAY VIEW/EDIT/INVOKE 
        // *************************************************************** 

        var myName=n?n:"John Doe";

        // *************************************************************** 
        // PRIVILEGED METHODS 
        // MAY BE INVOKED PUBLICLY AND MAY ACCESS PRIVATE ITEMS 
        // MAY NOT BE CHANGED; MAY BE REPLACED WITH PUBLIC FLAVORS 
        // *************************************************************** 
        this.toString=this.getName=function(){ return myName } 
    } 
    return PersonConstructor;
})();

var person1 = new Person("foo");
var person2 = new Person("bar");

alert(person1.getName());
alert(person1.toString());
alert(person1.myName);

// alerts "foo", "foo", undefined

编辑 - 这是我原来的解决方案。

var Person = function(n){ 
    // *************************************************************** 
    // PRIVATE VARIABLES AND FUNCTIONS 
    // ONLY PRIVELEGED METHODS MAY VIEW/EDIT/INVOKE 
    // *************************************************************** 

    var myName=n?n:"John Doe";

    // *************************************************************** 
    // PRIVILEGED METHODS 
    // MAY BE INVOKED PUBLICLY AND MAY ACCESS PRIVATE ITEMS 
    // MAY NOT BE CHANGED; MAY BE REPLACED WITH PUBLIC FLAVORS 
    // *************************************************************** 
    this.toString=this.getName=function(){ return myName } 

} 

var person1 = new Person("foo");
var person2 = new Person("bar");

alert(person1.getName());
alert(person1.toString());
alert(person1.myName);

// alerts "foo", "foo", undefined

【讨论】:

  • 特权方法和公共方法根本不能很好地协同工作。
  • @Raynos - 对我来说似乎工作正常。就个人而言,我会取消prototype.getName,但它是OP设计的一部分,所以我想我会把它留在那里。
  • 您的特定示例将更适合公共只读属性。在现实世界的场景中,这是行不通的
  • @Raynos - 就像我说的那样,它被留下作为替代方案,以表明prototype.getName 确实有效并且私有变量myName 只是一个范围问题。
  • @Raynos - 实际上,与使用状态对象的公认答案相比,它非常简单(哦,那是你的)。我想发布一个非常非常简单的版本,但它没有使用“PersonConstructor”和OP想要的原型东西。我已经做 OO JS 大约 15 年了,并且知道我在做什么。简单更好。
【解决方案3】:

使用原型时没有“私有”。

需要注意的是,私有状态没有任何价值,像瘟疫一样避免它。闭包既丑陋又昂贵。

var o = {
    name: value
}

但是,如果你坚持妄想并且非常想要私人状态,那么

您可以将状态存储在闭包中

function nameHolder(name) {
    return {
        get name() {
            return name
        },
        set name(n) {
            name = n
        }
    }
}

请注意,这是非常低效的,几乎没有什么好处。

或者,您可以将状态存储在弱映射中

function privates() {
    var map = new WeakMap()

    return function (key) {
        var v = map.get(key)
        if (!v) {
            v = {}
            map.set(key, v)
        }
        return v
    }
}

var NameHolder = (function () {
    var state = privates()

    return {
        constructor: function (name) {
            state(this).name = name
        },
        getName: function () {
            return state(this).name
        }
    }
}())

WeakMap 浏览器支持不存在,因此使用pd.Name 模拟它

【讨论】:

  • 你能详细说明一下吗?所以对于每个变量我可能想保持“私有”(抱歉不知道如何引用它)我必须创建一个持有者函数?编辑:好的,我看到了你的阐述,我会试试这个,虽然我必须先试着理解它。
  • 我很惊讶@Raynos 对私有状态的使用没有更积极的态度。这是一个足够公平的问题,但问问你自己,你真的需要私有状态吗?您可以遵循使用前导下划线标记所有内部不可混淆变量的约定。可能更容易调试,效率更高。
  • 您声称关闭既丑陋又昂贵。确实,跨越范围边界进行引用查找是有成本的,但在编写良好的代码中,可以最大限度地降低成本,而在现代 JIT 解释器中,它通常在循环之外是无关紧要的。闭包可能是 JavaScript 中最优雅和最具表现力的特性。闭包使得一个 2000 行的 Java 程序在 JavaScript 中只有 500 行。
  • 闭包与此无关。一等函数很强大,过度使用闭包会导致糟糕的代码(在 OO 风格中。在函数式代码中有效使用闭包效果很好)。您还应该自己对其进行基准测试,它们仍然具有显着的性能和复杂性损失
  • 当问题只是错误的范围时太复杂了。当原始代码的范围正确时,一切都按预期工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-08-04
  • 1970-01-01
  • 2013-05-03
  • 2017-10-16
  • 2016-10-28
  • 2010-10-07
相关资源
最近更新 更多