2009-10-28 53 views
91

Possible Duplicate:
Simplest/Cleanest way to implement singleton in JavaScript?的Javascript:最好Singleton模式

我用这个模式来单身,本例中的单是地球脉动:

var NAMESPACE = function() { 

    var privateFunction1 = function() { 
     privateFunction2(); 
    }; 

    var privateFunction2 = function() { 
     alert('I\'m private!'); 
    }; 

    var Constructors = {}; 

    Constructors.PlanetEarth = function() { 
     privateFunction1(); 
     privateFunction2(); 
    }; 

    Constructors.PlanetEarth.prototype = { 
     someMethod: function() { 
      if (console && console.log) { 
       console.log('some method');    
      } 
     } 
    }; 

    Constructors.Person = function (name, address) { 
     this.name = name; 
     this.address = address; 
    }; 

    Constructors.Person.prototype = { 
     walk: function() { 
      alert('STOMP!'); 
     } 
    }; 

    return { 
     Person: Constructors.Person, // there can be many 
     PlanetEarth: new Constructors.PlanetEarth() // there can only be one! 
    }; 

}(); 

由于地球脉动的构造保持私密,也只能是一个。

现在,有人告诉我,这种自制的东西并不是最好的,主要是因为我没有学历教育,而且我倾向于用愚蠢的方式解决问题。你会提出什么样的更好替代我的方法,其中更好被定义为风格上更好和/或更强大

回答

24

为什么要为单个对象使用构造函数和原型?

以上等同于:

var earth= { 
    someMethod: function() { 
     if (console && console.log) 
      console.log('some method');        
    } 
}; 
privateFunction1(); 
privateFunction2(); 

return { 
    Person: Constructors.Person, 
    PlanetEarth: earth 
}; 
+13

如果这是包含在页面上两次,最新的对象将覆盖前面的。实际上,它发生 - 有时会产生意想不到的后果。单身封闭模式可以阻止这种情况所以,如果你发布一个脚本/库,它将优雅地处理其他使用它的人的滥用。正因如此,大部分Google的API库都这样做。假设我在网站上使用Google地图,但希望通过一些第三方来安装widget,其中也明确包含地图库。我是否需要更改第三方代码,或者库本身是否应该优雅地处理这个问题? – defines 2013-04-17 14:36:05

+10

如果你使用:var earth = earth || {....}; – chees 2013-09-13 13:01:21

+3

如果您使用的是正确的文件管理器,如requirejs,它也不会覆盖它。 – mwilcox 2013-09-25 22:19:46

146

找到最好的解决办法: http://code.google.com/p/jslibs/wiki/JavascriptTips#Singleton_pattern

function MySingletonClass() { 

    if (arguments.callee._singletonInstance) { 
    return arguments.callee._singletonInstance; 
    } 

    arguments.callee._singletonInstance = this; 

    this.Foo = function() { 
    // ... 
    }; 
} 

var a = new MySingletonClass(); 
var b = MySingletonClass(); 
console.log(a === b); // prints: true 

对于那些谁想要严格的版本:

(function (global) { 
    "use strict"; 
    var MySingletonClass = function() { 

    if (MySingletonClass.prototype._singletonInstance) { 
     return MySingletonClass.prototype._singletonInstance; 
    } 

    MySingletonClass.prototype._singletonInstance = this; 

    this.Foo = function() { 
     // ... 
    }; 
    }; 

var a = new MySingletonClass(); 
var b = MySingletonClass(); 
global.result = a === b; 

} (window)); 

console.log(result); 
+50

以严格版本更新,先生。请将该投票撤回。 – 2012-06-29 06:26:37

+0

难道这不仅仅是MySingletonClass.prototype._singletonInstance = 1; ? – sivann 2012-07-10 19:59:47

+0

@sivann然后你将如何返回第一个实例? – 2012-09-12 00:48:36

18

Extending上述职位由汤姆,如果你需要一个类型声明并使用变量访问单例实例,下面的代码可能会有所帮助。我喜欢这种表示法,因为代码很少有自我指导。

function SingletonClass(){ 
    if (arguments.callee.instance) 
     return arguments.callee.instance; 
    arguments.callee.instance = this; 
} 


SingletonClass.getInstance = function() { 
    var singletonClass = new SingletonClass(); 
    return singletonClass; 
}; 

要访问的单身,你会

var singleTon = SingletonClass.getInstance(); 
+5

真的,应该尽量避免使用'callee' - 来自MDN JavaScript严格模式引用(解释为什么在严格模式下不支持被调用者) - “在正常的代码参数中..callee指的是封闭函数,这个用例很弱:只需命名封闭函数!另外,arguments.callee会严重阻碍内联函数等优化,因为如果访问arguments.callee,必须提供对未内联函数的引用。 – defines 2013-04-15 20:04:44

1
function SingletonClass() 
{ 
    // demo variable 
    var names = []; 

    // instance of the singleton 
    this.singletonInstance = null; 

    // Get the instance of the SingletonClass 
    // If there is no instance in this.singletonInstance, instanciate one 
    var getInstance = function() { 
     if (!this.singletonInstance) { 
      // create a instance 
      this.singletonInstance = createInstance(); 
     } 

     // return the instance of the singletonClass 
     return this.singletonInstance; 
    } 

    // function for the creation of the SingletonClass class 
    var createInstance = function() { 

     // public methodes 
     return { 
      add : function(name) { 
       names.push(name); 
      }, 
      names : function() { 
       return names; 
      } 
     } 
    } 

    // wen constructed the getInstance is automaticly called and return the SingletonClass instance 
    return getInstance(); 
} 

var obj1 = new SingletonClass(); 
obj1.add("Jim"); 
console.log(obj1.names()); 
// prints: ["Jim"] 

var obj2 = new SingletonClass(); 
obj2.add("Ralph"); 
console.log(obj1.names()); 
// Ralph is added to the singleton instance and there for also acceseble by obj1 
// prints: ["Jim", "Ralph"] 
console.log(obj2.names()); 
// prints: ["Jim", "Ralph"] 

obj1.add("Bart"); 
console.log(obj2.names()); 
// prints: ["Jim", "Ralph", "Bart"] 
+2

是不是一个你没有明确实例化它的单例的关键,是(a)只有一个实例(这就是为什么叫做SINGLEton)和(b)它是在全局命名空间中自动声明的?对我来说,Lecleuse先生的模式是为了“阶级”而不是单身。 – dlchambers 2012-05-11 21:07:44

+3

这段代码实际上是相当危险的误导。 'getInstance'函数中的'this'实际上是指全局对象(浏览器中的'window')。基本上,'singletonInstance'泄漏到全局范围 - 如果你有多个这样的类,使用'singletonInstance'这个名字,祝你好运。在严格模式下,你会得到'TypeError:这是未定义的',并且正确的! – smitelli 2012-10-02 17:08:19