用JavaScript实现单例模式的最简单/最干净的方法是什么?


当前回答

function Unicode()
{
  var i = 0, unicode = {}, zero_padding = "0000", max = 9999;

  // Loop through code points
  while (i < max) {
    // Convert decimal to hex value, find the character,
    // and then pad zeroes to the code point
    unicode[String.fromCharCode(parseInt(i, 16))] = ("u" + zero_padding + i).substr(-4);
    i = i + 1;
  }

  // Replace this function with the resulting lookup table
  Unicode = unicode;
}

// Usage
Unicode();

// Lookup
Unicode["%"]; // Returns 0025

其他回答

我发现下面是最简单的单例模式,因为使用new操作符可以立即在函数中使用它,消除了返回对象字面量的需要:

Var singleton = new(函数(){ var private = "一个私有值"; 这一点。printSomething = function() { console.log(私人); } }) (); singleton.printSomething ();

我不确定我是否同意用模块模式来代替单例模式。我经常看到单例对象在完全没有必要的地方被使用和滥用,我确信模块模式填补了程序员使用单例对象的许多空白。然而,模块模式不是单例的。

模块模式:

var foo = (function () {
    "use strict";
    function aPrivateFunction() {}
    return { aPublicFunction: function () {...}, ... };
}());

在模块模式中初始化的所有内容都在声明Foo时发生。此外,模块模式可用于初始化构造函数,然后可以多次实例化构造函数。虽然模块模式是许多工作的正确工具,但它并不等同于单例模式。

单例模式:

简式

var Foo = function () {
    "use strict";
    if (Foo._instance) {
        // This allows the constructor to be called multiple times
        // and refer to the same instance. Another option is to
        // throw an error.
        return Foo._instance;
    }
    Foo._instance = this;
    // Foo initialization code
};
Foo.getInstance = function () {
    "use strict";
    return Foo._instance || new Foo();
}

长格式,使用模块模式

var Foo = (function () {
    "use strict";
    var instance; //prevent modification of "instance" variable
    function Singleton() {
        if (instance) {
            return instance;
        }
        instance = this;
        //Singleton initialization code
    }
    // Instance accessor
    Singleton.getInstance = function () {
        return instance || new Singleton();
    }
    return Singleton;
}());

在我提供的两个版本的单例模式中,构造函数本身都可以用作访问器:

var a,
    b;
a = new Foo(); // Constructor initialization happens here
b = new Foo();
console.log(a === b); //true

如果你不习惯这样使用构造函数,你可以在If (instance)语句中抛出一个错误,并坚持使用长形式:

var a,
    b;
a = Foo.getInstance(); // Constructor initialization happens here
b = Foo.getInstance();
console.log(a === b); // true

我还应该提到,单例模式很适合隐式构造函数模式:

function Foo() {
    if (Foo._instance) {
        return Foo._instance;
    }
    // If the function wasn't called as a constructor,
    // call it as a constructor and return the result
    if (!(this instanceof Foo)) {
        return new Foo();
    }
    Foo._instance = this;
}
var f = new Foo(); // Calls Foo as a constructor
-or-
var f = Foo(); // Also calls Foo as a constructor

单例模式:

确保一个类只有一个实例,并提供对它的全局访问点。

单例模式将特定对象的实例数量限制为一个。这个单一实例称为单例。

定义返回唯一实例的getInstance()。 负责创建和管理实例对象。

单例对象被实现为一个即时匿名函数。函数立即执行,将它括在括号中,然后再加上两个括号。它被称为匿名,因为它没有名字。

示例程序

var Singleton = (function () { var instance; function createInstance() { var object = new Object("I am the instance"); return object; } return { getInstance: function () { if (!instance) { instance = createInstance(); } return instance; } }; })(); function run() { var instance1 = Singleton.getInstance(); var instance2 = Singleton.getInstance(); alert("Same instance? " + (instance1 === instance2)); } run()

剥猫皮的方法不止一种:)根据你的口味或特定需求,你可以应用任何一种建议的解决方案。我个人倾向于Christian C. Salvadó的第一个解决方案(当你不需要隐私的时候)。

因为这个问题是关于最简单和最干净的,所以这个问题是赢家。甚至:

var myInstance = {}; // Done!

这(引用自我的博客)……

var SingletonClass = new function() {
    this.myFunction() {
        // Do stuff
    }
    this.instance = 1;
}

没有太大的意义(我的博客例子也没有),因为它不需要任何私有变量,所以它几乎与:

var SingletonClass = {
    myFunction: function () {
        // Do stuff
    },
    instance: 1
}

我认为最干净的方法是:

var SingletonFactory = (function(){
    function SingletonClass() {
        //do stuff
    }
    var instance;
    return {
        getInstance: function(){
            if (instance == null) {
                instance = new SingletonClass();
                // Hide the constructor so the returned object can't be new'd...
                instance.constructor = null;
            }
            return instance;
        }
   };
})();

之后,可以调用函数as

var test = SingletonFactory.getInstance();