2014-10-18 33 views
0

实例化后,“私人”成员(变量)是否可以添加到闭包中?Javascript:在关闭时,实例化后可以添加私有成员(var`s)吗?

我想我明白了这么多下面我闭幕(请纠正我,如果我错了!):

  • this.x可用“公开”

  • var y不可公开,但

    :可通过this.y()

  • new Closure()后,我可以添加一个新的 “公共” 这样的访问

    var c=new Closure(); 
    c['z']=25; 
    console.log(c.z); // z is a dynamically added public member 
    

所以...有没有一种方法来动态添加一个私有成员(VAR)和 “新-ING” 关闭后其get/set函数?

var Closure=(function(){ 

    function Closure(x){ 
     // "public" member 
     this.x=x; 
    }; 

    // "private" member backing variable 
    var _y=0; 

    // get/set private member 
    Closure.prototype.y=function(newValue){ 
     if(newValue){ 
      _y=newValue; 
      return(this); 
     }else{ 
      return(_y); 
     } 
    }; 

    // return 
    return(Closure); 

})(); 


var c=new Closure(10,15); 

// Can I add var _z and it's get/set function at this point? 
+1

是的,您可以。只需创建一个新的闭包,并在该对象上添加私有变量的getter/setter函数。然而,新的私有变量只会在新的封闭中。它不会在旧的关闭。无论如何,你的用例是什么? – 2014-10-18 15:13:52

+0

@AaditMShah。感谢您的回应!那么如何在运行时动态地将'var z'添加到Closure中(请原谅我的“noobiness”)?我会将我的用例描述为“动态继承”。我想从一个基本的Closure开始,并根据需要动态添加成员(public和private)。 – JustAsking 2014-10-18 15:23:27

+0

我会做类似'(function(c,z){cz = function(v){if(arguments.length){z = v; return c;} else return z;};}(c,null)) '。但是,你真的需要私有变量吗?考虑一下:你已经让程序员用getter和setter来设置'z'的值。那么为什么不把它公开呢?而且,继承和OOP不是99%用例的解决方案。你应该看一看代数数据类型:https://en.wikipedia.org/wiki/Algebraic_data_type – 2014-10-18 15:42:46

回答

1

var y is unavailable publicly

but can be accessed through this.y()

this通常是一个对象,并.y总是属性参考。它永远不能用于访问y变量

Is there a way to dynamically add a private member (var) and its get/set function after "new-ing" the Closure?

号当Closure()函数被调用(在你的情况下,一个构造函数),它与所有的变量范围(x)结算,不能修改。

对于那个IIFE也是一样,它的执行引入了后来解决的当地Closure_y变量。

什么,但是你可以做的是增加一个的getter/setter对,有它自己的范围内(其中可能有额外的“私有”变量),但它是不可能的访问_y变量或操纵范围它位于外面。

function Scope(x, y) { 
    // "public" member 
    this.x = x; 

    // private "member" 
    var _y = y; 

    // accessors: 
    this.setY = function(newValue) { _y = newValue; }; 
    this.getY = function() { return _y; }; 
    // '_y' is still accessible here ^^ 
    // through closure of the two functions, which can access their parent scope 
} 
var c = new Scope(10, 15); 
c.x // 10 
c.getY() // 15 

这里没有办法修改,其中_y(和xy)所在的范围。但是,我们可以在c中添加一个新字段,即使其变量不会处于相同范围内:

function addZ(obj, z) { 
    // new scope, private variable: 
    var _z = z; 

    obj.getZ = function() { return _z; } 
    // setter analogous if you want one 
} 
addZ(c, 12); 
c.getZ() // 12 
+0

不是这样,如果这些私有变量是数据结构,并且你提供访问方法访问闭包,它就可以正常工作。你也可以使用'eval()'来欺骗词法范围。你是否应该做这些事情是另一回事。 – 2014-10-18 15:34:09

+0

@JaredSmith:变量不是数据结构,它是*变量*。当然,如果它拥有一个结构,你可能会修改那个结构,但是你不能访问/设置*变量*,如果没有明确的关闭允许你这样做的话。 'eval'可以用于许多有趣的事情,但是你不能用它来修改已经存在的范围(除了“当前”,但这不是有趣的) – Bergi 2014-10-18 15:37:47

+0

我看到...所以Closure不会接受新的'var's之后实例。因此,要模仿动态添加的变量,您是否赞同包含键值对的私有对象文字的概念。当需要一个新的“私有”时,只需在私有对象文本上推一个新的键值,并有一个getter/setter来获取任何指定的键值。这将类似于asp.net MVC中的ViewBag。还是有更受欢迎的方式? – JustAsking 2014-10-18 15:43:40

0

是的。有点。您可以创建一个私有对象或数组,并提供添加到其中的方法。

使用WeakMap

function myClosure() { 
    var hidden = new WeakMap(); 
    var obj = { 
     addPrivate: function(name, value) { 
      var privateData = hidden.get(this); 
      privateData[name] = value; 
     } 
    } 
    hidden.set(obj, {}); 
    return obj; 
} 

var foo = myClosure(); 
foo.addPrivate('bar', 7); 
foo.getBar = function() { 
    var priv = hidden.get(this); 
    return priv.bar; 
} 
foo.getBar(); //7 

一个更好的问题是,你应该这样做吗?答案一般不是。唯一一次我认为值得所有上述chichanery的不便之处是,当我有一个应用程序核心对象,我逐步增强异步扩展脚本(我使用WeakMap表单,如果我不需要担心旧版本的浏览器,如果我使用嵌套的obj文字)。

+0

你的第一个片段让我得到一个'语法错误:在'(var bar = 7);“中的索引1处:”expected“表达式,得到关键字'var'' – Bergi 2014-10-18 15:33:11

+0

即使你解决了这个问题,这会创建一个* global *'bar'变量,或者你的getBar函数不起作用。 – Bergi 2014-10-18 15:34:22

+1

不,它不起作用。您创建的'bar'存在于'addPrivate'范围内,* not *在'myClosure'中。并且这两个范围都不可用于'getBar'函数 - 这会引发参考错误。如果没有,这意味着你有一个全球性的“酒吧”躺在周围;请在全球范围内重新尝试。 – Bergi 2014-10-18 15:51:19