【问题标题】:Instances sharing prototype methods for use with private instance variables实例共享原型方法以用于私有实例变量
【发布时间】:2011-05-15 19:41:29
【问题描述】:

这个SO-question 一直困扰着我。这是一个在 SO 中似乎经常出现的问题。

现在我设计了一种方法来创建构造函数,试图管理只能从构造函数原型 get/set 方法中使用私有存储来设置私有“属性”。它的基本形式如下所示:

基本构造函数:

function Human(){
   /** set up a property storage **/   
   var storage = {
      name: { val: name || '-', get:true, set:true }
      ,age: { val: (age || '0'), get:true, set:true }
   };
   function get(){
       if (get.caller !== Human.prototype.get &&
           get.caller !== Human.prototype.set ){ return null }
       return storage;
   }
   this._get = get;
}

Human添加get/set原型方法

Human.prototype = {
     get: function(prop){
        return this._get()[prop];
     }
    ,set: function(prop, val){
       var storage = this._get();
       /** 
              set functionallity, returning 
              the current object after setting
              see jsfiddle link @ the bottom of
              this question
        **/
       return this;
    }
};
// usage
var pete = new Human('Pete',23);
pete.get('name'); //=> 'Pete'
pete.set('name','Pete Justin');
pete.get('name'); => 'Pete Justin'
// but
pete.name; //=> 'undefined'

我对你们的 cmets 真的很感兴趣。也许我在想一个完全错误的方向,也许你说这是一个不必要的操作,违反了 js 的原型性质,它已经在其他地方做过(并且更好),或者任何事情。请告诉我!

我对此的看法 - 好吧,我们称之为 - 模式:您使用它松散的是简单地声明和获取属性(this.some = that 等),您赢得的是更好的封装、实例变量的隐私以及对您使用的属性的一些控制(不确定这是否是正确的术语,但在 OOP 世界中,有时看起来每个人都对术语赋予了自己的私人含义)。

不管怎样,我已经在this jsfiddle 中制作了一个更完整、更有效的Human

【问题讨论】:

  • 我很好奇构造函数中立即调用函数的原因。似乎您可以将storage设为构造函数私有,然后直接公开get方法this._store = {get: get};。但也许我错过了一些东西。另外,我认为.caller 属性的日子已经过去了。你会在"strict mode"; 中得到一个TypeError
  • @patrick:afaik 的日子是为arguments.caller 编号的,而不是function.caller。是的,storage 也可以是构造函数本身的私有变量,很好的调用。它在 iif 中(不,这不是 ms-access;)是所有摆弄的残余。没有特别的理由。 iif 可以被抛弃,正如这个 fork 所示:jsfiddle.net/KooiInc/H2fU5
  • 我不想这么说,但在15.3.5 Properties of Function Instances 你会发现:"对应于严格模式函数(13.2)的函数实例和使用Function.prototype.bind 创建的函数实例方法 (15.3.4.5) 具有名为“caller”和“arguments”的属性,它们会引发 TypeError 异常。ECMAScript 实现不得将任何特定于实现的行为与从严格模式函数代码对这些属性的访问相关联。
  • @patrick:保持冷静,我从不向信使开枪。是的,你是对的。如果您在我创建的小提琴中添加严格模式,您可以在 FF4 中测试您的正确性(正义?我是荷兰人,抱歉)。现在我将省略严格模式。你会碰巧知道一个可行的替代方案吗?
  • @KooiInc:我认为你在寻找“正确性”,因为没有一个是正义的,不,没有一个。 :o)

标签: javascript prototype-programming private-members


【解决方案1】:

首先,这个过度设计的解决方案试图解决什么问题?

尝试从原型访问构造函数局部变量的问题不是问题。人们要么只需要使用原型并将所有数据存储在this 上以获得较小的速度增益,要么不必抱怨为每个对象创建额外的函数(最小开销)。一个常见的误解是为每个对象创建额外的函数很昂贵。


无意冒犯,但代码设计过度、复杂,阅读或维护似乎很痛苦。我看不出这种方法有什么好处?为什么不将this._store 设为特权函数。

此外,您在构造函数中有一个本地函数这一事实意味着您失去了对所有对象都具有一个函数的原型的优势。我还过度设计了一个类似的解决方案来“模拟”私有变量,代码变得一团糟,我不得不放弃它。


至于代码批评:

.caller 是非标准的。你不能使用它。这是一个黑客。

this._store = {get:get};

为什么不只是this._store = get

这个

function thisget(prop){
    return storage[prop];
}
return thisget(prop);

应该内联到

return storage[prop]

【讨论】:

  • 我倾向于同意。即使除了caller 问题和代码样式问题之外,如果安全是目标,则可以通过将Human.prototype 中的getset 方法替换为您自己的调用this._store.get() 的方法来覆盖它。跨度>
  • 谢谢雷诺斯。是的,它是过度设计的。更多的是关于想法,当然必须优化代码。我正在使用非标准但广泛使用(且可用)Function.caller,如下所述:developer.mozilla.org/en/JavaScript/Reference/Global_Objects/…。如果有人有替代方案,我很高兴听到。
  • @Kooilnc 别无选择。你试图达到的目标是无法实现的,也不需要实现。你剩下的就是意大利面条代码:)
  • @Raynos:我同意不需要的部分,真的。但是这个问题经常在这里@ SO,我想检查所有的可能性。如果有这么多人要求将私有(或者我必须说经典 OOP)的东西压缩到原型模型中,你就会开始怀疑你是那个不明白的人。我承认,这很可能是个例。
  • @patrick:您的 正确性 是压倒性的 ;~) 请参阅我对 Raynos 评论的回答。安全不是(我的)问题。这种模式可能仍然存在恕我直言(我顺便简化了小提琴)可能是您对设置/获取属性的控制权,即使我们放弃了.caller
猜你喜欢
  • 1970-01-01
  • 2011-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-10
  • 2013-07-07
  • 1970-01-01
相关资源
最近更新 更多