将大变量存储在闭包中会导致问题吗?

6

我有一个函数,其中使用了闭包,具体如下:

function myobject() {
  var width=300,
      height=400,
      bigjsondata = { } // assume this is a big variable ~ 300k

  function obj(htmlelement) {
     // plot a graph in this htmlelement based on bigjsondata
  }

  return obj;
}

var plot1 = myobject();
plot1('#holder1');

var plot2 = myobject();
plot1('#holder2');

变量bigjsondata包含一个大数据集。问题是:每当我创建变量var a = myobject()时,它是否会为bigjsondata分配内存?如果创建了很多实例,这是否会导致内存问题?
如果是的话,最好的方法是什么?只加载一次(bigjsondata不会改变)。 编辑:最后,我希望myobject可以全局访问。

为什么你说当 obj.data 是一个 setter 函数时,bigjsondata 没有改变呢? - Bergi
你确定myobject应该返回obj函数吗? - Bergi
1
在 obj 函数中你做了什么?如果您能提供正确的代码,我们可以为您建议更好的方法。 - Parthik Gosar
300K真的是一个很大的对象吗?相当多的图像比这个要大得多! - Ed Heal
@EdHeal 好吧,那不是问题的重点,我想知道为什么需要将图像存储在这样的位置! - Nasir
显示剩余4条评论
3个回答

3

通常情况下,是的,你的代码看起来每次使用 new myObject(); 时都会创建一个新的 bigjsondata 实例。要解决这个问题,你可以像这样使用匿名初始化函数:

myObject = null;

(function() {
     var bigjsondata = { ... } // construct you large object here;

     function myObjectInternal() {
         // you can access `bigjsondata` from here.
         // do not change `bigjsondata`, since it will now 
         // use the changed value in all new instances of `myObjectInternal`
     }
     myObjectInternal.prototype = {
         data: function(_) {
             // you can access `bigjsondata` from here too
         }
     };

     myObject = myObjectInternal;
})();

这将创建一个立即调用且仅调用一次的匿名函数(类似单例模式)。在该函数内,bigjsondata是对myObjectInternal函数的闭包引用,该函数只在匿名函数中可见。这就是为什么要定义外部全局变量myObject,以便稍后将其指向myObjectInternal函数/对象。
像定义myObject一样定义myObjectInternal,然后你就可以使用它了。因此,在下面的代码中:
var instance1 = new myObject();
var instance2 = new myObject();

它将使用相同的bigjsondata来为instance1instance2提供支持。


你能否给出一个示例代码,说明如何从“instance1”和“instance2”访问bigjsondata? - ducin
1
@tkoomzaaskz,上面的代码没有暴露bigjsondata,而且在回答时OP的问题并没有暗示它应该被暴露。如果您需要它,您需要在myObject原型中提供一个getter函数,像这样:myObjectInternal.prototype.getData = function() { return bigjsondata; },然后您可以调用instance1.getData();来获取它。 - Ivaylo Slavov
1
是的,我知道问题在此期间已被更改。但幸好有这段代码 - 现在我明白了这个想法,谢谢。 - ducin

3

我不确定你想要实现什么,但这可以为你提供不同级别的私人存储:

var privateStorage = function () {
  // only 1 copy total
  var bigJsonData = {...}
  return function() {
    // 1 copy for each instance
    var instanceData = {...}
    return function() {
          // something to do many times per instance
          return something_useful
    }
  }
}(); // returns function that privatelly knows about bigJsonData

var a = privateStorage(); // a is now 1st instance of the inner-most function
var b = privateStorage(); // a and b share the SAME bigJsonData object, but use different instanceData objects

a1 = a();
a2 = a();

返回函数而不是我在答案中使用的内容,加1。 - Ivaylo Slavov

1
我建议采用面向对象的方法来解决这个问题。
function obj (htmlelement)
{
    this.htmlelement = $(htmlelement);    
}

obj.prototype.htmlelement = null;
obj.prototype.bigjsondata = {};
obj.prototype.width = 300;
obj.prototype.height=400;

obj.prototype.plot = function ()
{
   var htmlelement = this.htmlelement;
   var bigjsondata = this.bigjsondata;
   var width = this.width;
   var height = this.height;
   //plot graph here;
}

var plot1  = new obj('#holder1');
var plot2 = new obj('#holder2');
plot1.plot();
plot2.plot();

在这里,obj的所有对象将共享相同的bigjsondata。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接