在javascript中有条件地实例化模块模式的一个实例

在javascript中有条件地实例化模块模式的一个实例,javascript,module-pattern,Javascript,Module Pattern,我试图公开一个模块。我只想向所有调用者公开它的一个实例,我想等到模块被调用后再实例化它。我试着这样做: var obj = {}; var foobar = function(){ var id=22; function GetId(){ return ++id; } return{ GetId: GetId }; }; obj.foobar = (function(){ if (obj.foobar instanceof foobar) { return o

我试图公开一个模块。我只想向所有调用者公开它的一个实例,我想等到模块被调用后再实例化它。我试着这样做:

var obj = {};

var foobar = function(){
 var id=22;
 function GetId(){ return ++id; }
 return{ GetId: GetId };
};

obj.foobar = (function(){
    if (obj.foobar instanceof foobar) {
         return obj.foobar;
    }
    return new foobar();
})();

console.log(obj.foobar.GetId());//23
console.log(obj.foobar.GetId());//24
但实际上,这只是一个模糊的概念

obj.foobar = new foobar();
我本来打算在第一次调用
obj.foobar.GetId()
时实例化
obj.foobar=new foobar()
,第二次调用
obj.foobar.GetId()
时使用已经实例化的版本。虽然这里不存在,但是有些依赖项需要等待实例化
newfoobar()因此无法立即执行

我怎样才能做到这一点,我错过了什么

我本来打算在第一次调用
obj.foobar.GetId()
时实例化
obj.foobar=newfoobar()

不,那不行。如果调用
getId
方法,则必须已经存在一个对象。您可以为
obj
foobar
属性定义一个getter函数,该属性在访问时创建实例,或者您之前只是实例化了它(正如您在IEFE中所做的那样,并且可以像您所说的那样对赋值进行更短的操作)

通常,您会使用每次调用的函数(也可以是构造函数),如果已经创建了单例,则返回单例,否则它将创建一个单例并存储它:

var obj = {
    foobar: (function iefe() {
        var id, instance;
        return function constructor() {
            if (!instance) { // create it
                id = 22;
                instance = {
                    getId: function getID(){
                        return ++id;
                    }
                };
            }
            return instance;
        };
    })();
};

obj.foobar().getId() // 23
obj.foobar().getId() // 24

每次访问
foobar
时都可以使用函数调用:

obj.foobar = (function() {
  var inst;
  return function() {
    return inst || (inst = foobar());
  };
})();

console.log(obj.foobar().GetId()); // 23
如果目标执行环境支持ECMAScript 5的命名访问器属性,也可以使用它们:

Object.defineProperty(obj, "foobar", {
  get: (function() {
    var inst;
    return function() {
      return inst || (inst = foobar());
    };
  })()
});

console.log(obj.foobar.GetId()); // 23
或者,如果您知道可以在
foobar
上调用的方法列表,您可以使用更复杂的解决方案:

obj.foobar = (function() {
  var inst, res = {}, methods = ["GetId"];
  function createLazyMethod(method) {
    return function() {
      if (!inst) {
        obj.foobar = inst = foobar();
      }

      return inst[method].apply(inst, methods.slice.call(arguments, 0));
    };
  }

  for (var i = 0; i < methods.length; ++i) {
    res[methods[i]] = createLazyMethod(methods[i]);
  }

  return res;
})();

console.log(obj.foobar.GetId()); // 23
obj.foobar=(函数(){
var inst,res={},methods=[“GetId”];
函数createLazyMethod(方法){
返回函数(){
如果(!inst){
obj.foobar=inst=foobar();
}
返回inst[method].apply(inst,methods.slice.call(arguments,0));
};
}
对于(变量i=0;i
使用此解决方案,一旦实例化了
foobar
,对其方法的调用成本为零