在JavaScript中实现单例的最简单/最简洁的方法?

Jak*_*old 287 javascript singleton design-patterns function

在JavaScript中实现单例模式的最简单/最简洁的方法是什么?

CMS*_*CMS 304

我认为最简单的方法是声明一个简单的对象文字:

var myInstance = {
  method1: function () {
    // ...
  },
  method2: function () {
    // ...
  }
};
Run Code Online (Sandbox Code Playgroud)

如果您想在单例实例上使用私有成员,可以执行以下操作:

var myInstance = (function() {
  var privateVar = '';

  function privateMethod () {
    // ...
  }

  return { // public interface
    publicMethod1: function () {
      // all private members are accesible here
    },
    publicMethod2: function () {
    }
  };
})();
Run Code Online (Sandbox Code Playgroud)

这就是所谓模块模式,它基本上可以让你来封装对象私有成员,通过采取利用的优势关闭.

  • 这不应该是公认的答案.这根本不是单身人士!这只是一个全局变量.两者之间存在着天壤之别. (47认同)
  • +1在具有全局变量的语言中寻找"单例模式"是不是有点奇怪? (46认同)
  • @Victor - 在这种语言中寻找"单例模式"并不奇怪.许多面向对象语言利用全局变量,并且仍在使用单例.Singleton不仅保证只有一个给定类的对象.Singleton有更多的功能:1)它应该在第一次使用时初始化(这不仅意味着延迟初始化,而且还保证对象真的可以使用)2)它应该是线程安全的.模块模式可以替换单例模式,但仅限于浏览器(并非总是如此). (14认同)
  • 使用模块模式,公共成员如何访问另一个公共成员?即,`publicMethod1`如何调用`publicMethod2`? (4认同)
  • @Tom,是的,模式诞生于基于类的OOP语言 - 我记得很多实现涉及静态`getInstance`方法和私有构造函数 - 但IMO,这是最"简单"的构建方式Javascript中的单例对象,最后它满足相同的目的 - 一个单独的对象,你不能再次初始化(没有构造函数,它只是一个对象) - .关于你链接的代码,它有一些问题,交换`a`和`b`变量声明并测试`a === window`.干杯. (4认同)
  • @skalee 感谢您的评论。尽管如此,我还是觉得围绕模式有太多的货物崇拜行为,而很少考虑你真正需要什么以及你已经拥有什么工具。 (2认同)
  • @mlibby singleton是一种设计模式,通过使用Java名称空间是全局的事实来使同一实例在多个类中可用-尽管如此,它是一个全局变量-http://misko.hevery.com/2008/08/17/singletons-是病理性骗子/ (2认同)
  • @BenjaminGruenbaum 不。不是。全局变量是一个全局变量。我们已经对此有了一个说法。如果 Java 没有全局变量,我可以看到使用 Singleton 来获取它们的吸引力,但 Singleton 作为一种模式出现在 Java 语言之前。单例模式不仅仅是关于实例的全局可用性,而是关于限制给定类的实例数量。因此,这个答案现在甚至 _less__ 正确,因为 JavaScript 具有 `class` 关键字,而不是在 2013 年我对它提出问题时。 (2认同)

seb*_*eli 166

我认为最干净的方法是这样的:

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;
        }
   };
})();
Run Code Online (Sandbox Code Playgroud)

之后,您可以调用该函数

var test = SingletonFactory.getInstance();
Run Code Online (Sandbox Code Playgroud)

  • 备注:可以使用`delete instance.constructor`再次读取原始构造函数:`x = SingletonClass.getInstance(); delete x.constructor; new x.constructor;` (4认同)
  • 整个"getInstance"部分让我觉得更像工厂. (3认同)
  • 这不是单例,因为您可以使用 Object.create 创建它的多个实例。 (2认同)

zzz*_*Bov 101

我不确定我是否同意将模块模式用作单例模式的替代品.我经常看到在完全没有必要的地方使用和滥用单身人士,我确信模块模式填补了程序员否则会使用单例的许多空白,但模块模式不是单例.

模块模式:

var foo = (function () {
    "use strict";
    function aPrivateFunction() {}
    return { aPublicFunction: function () {...}, ... };
}());
Run Code Online (Sandbox Code Playgroud)

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();
}
Run Code Online (Sandbox Code Playgroud) 长形式,使用模块模式
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;
}());
Run Code Online (Sandbox Code Playgroud)

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

var a,
    b;
a = new Foo(); //constructor initialization happens here
b = new Foo();
console.log(a === b); //true
Run Code Online (Sandbox Code Playgroud)

如果您不习惯使用构造函数,则可以在if (instance)语句中抛出错误,并坚持使用long形式:

var a,
    b;
a = Foo.getInstance(); //constructor initialization happens here
b = Foo.getInstance();
console.log(a === b); //true
Run Code Online (Sandbox Code Playgroud)

我还要提一下,单例模式非常适合隐式构造函数模式:

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
Run Code Online (Sandbox Code Playgroud)

  • @Esailija,听起来像你不理解单身模式.单例模式是一种设计模式,它将类的实例化限制为一个对象.`var singleton = {}`不符合该定义. (10认同)
  • 由于它们的局限性,这仅适用于Java等语言.[`var singleton = {}`是你在Javascript中实现单例的方式](http://en.wikipedia.org/wiki/Singleton_pattern#Prototype-based_singleton). (8认同)
  • 我从来没有说过关于单身人士是坏主意还是好主意的事情.我说你的单例实现远比它需要的复杂得多,因为你把Java的局限性与模式混淆了,好像你根本就不理解它一样.这就像通过制作构造函数和方法来实现策略模式,只需在Javascript中使用匿名函数即可. (4认同)
  • 顺便说说.Singleton是一种反模式,无论如何都不应该在像JavaScript这样的托管沙盒环境中使用.http://misko.hevery.com/2008/08/17/singletons-are-pathological-liars/ - http://youtube.com/watch?v=G32acYVd9LY http://blogs.msdn.com/b/ scottdensmore/archive/2004/05/25/140827.aspx - http://jalf.dk/blog/2010/03/singletons-solving-problems-you-didnt-know-you-never-had-since-1995/ - http://kore-nordmann.de/blog/0103_static_considered_harmful.html - http://www.phparch.com/2010/03/static-methods-vs-singletons-choose-neither/ (3认同)
  • @Esailija,"在基于原型的编程语言中,使用对象但不使用类......"JavaScript具有类的概念,因此不适用. (2认同)
  • @FlorianMargaine,JS 通过构造函数实例化具有类的 **概念**。它们并不完全是强类型 OOP 语言(例如 Java 或 C#)所使用的类。 (2认同)
  • @FlorianMargaine,现在看到您的评论,因为[classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes)已被标准化为我已经拥有的原型功能的语法糖多年的使用使我感觉很领先。为此,我应该感谢你。 (2认同)

Utk*_*pta 42

ES6 中,正确的方法是:

class MyClass {
  constructor() {
    if (MyClass._instance) {
      throw new Error("Singleton classes can't be instantiated more than once.")
    }
    MyClass._instance = this;

    // ... Your rest of the constructor code goes after this
  }
}

var instanceOne = new MyClass() // Executes succesfully
var instanceTwo = new MyClass() // Throws error
Run Code Online (Sandbox Code Playgroud)

或者,如果您不希望在创建第二个实例时抛出错误,您可以只返回最后一个实例,如下所示:

class MyClass {
  constructor() {
    if (MyClass._instance) {
      return MyClass._instance
    }
    MyClass._instance = this;

    // ... Your rest of the constructor code goes after this
  }
}

var instanceOne = new MyClass()
var instanceTwo = new MyClass()

console.log(instanceOne === instanceTwo) // Logs "true"
Run Code Online (Sandbox Code Playgroud)

  • `instance` 和 `_instance` 没有技术上的区别。这只是编程语言中的命名约定,我们将以下划线命名为“私有”变量。我怀疑您的代码无法工作的原因是您使用的是“this.instance”而不是“MyClass.instance” (4认同)
  • 您是否缺少“static getInstance()”方法?或者说你如何使用这个实现? (4认同)
  • 这可以通过使用保存实例的静态私有变量来改进,例如“static #instance = null;”。否则,只需修改“_instance”属性(将其设置为“null”)即可创建第二个实例。 (3认同)

iaf*_*rek 31

如果您正在使用,node.JS那么您可以利用node.JS 缓存机制和您的Singleton将非常简单:

\n
class Singleton {\n    constructor() {\n        this.message = \'I am an instance\';\n    }\n}\nmodule.exports = new Singleton();\n
Run Code Online (Sandbox Code Playgroud)\n

请注意,我们导出不是类而是实例 Singleton Singleton()

\n

Node.JS 每次需要时都会缓存并重用相同的对象。

\n

更多详情请查看:Node.JS 和 Singleton 模式

\n

  • 我也没有看到任何关于 node.js 的明确信息,也没有看到它 __must__ 是 vanilla JS。因此,我明确补充说,这是针对 JS 和 Node 的。如果你使用 Node.JS,你__不能__真正让它变得更简单、更干净!此外,从投票结果来看,发现这有帮助的人多于没有帮助的人。 (4认同)

Xaq*_*ron 14

es6:

class Singleton {
  constructor () {
    if (!Singleton.instance) {
      Singleton.instance = this
    }
    // Initialize object
    return Singleton.instance
  }
  // Properties & Methods
}

const instance = new Singleton()
Object.freeze(instance)

export default instance
Run Code Online (Sandbox Code Playgroud)

  • 如果 Singleton 是其他类的包装器并且只有 `instance` 字段,则冻结是有意义的。由于目前(`instance` 设置为`this`)这个类也可能有其他字段,并且冻结没有意义imo。 (4认同)

小智 12

如果你想使用类:

class Singleton {
  constructor(name, age) {
    this.name = name;
    this.age = age;
    if(this.constructor.instance)
      return this.constructor.instance;
    this.constructor.instance = this;
  }
}
let x = new Singleton('s', 1);
let y = new Singleton('k', 2);
Run Code Online (Sandbox Code Playgroud)

上述输出将是:

console.log(x.name, x.age, y.name, y.age) // s 1 s 1
Run Code Online (Sandbox Code Playgroud)

使用函数编写单例的另一种方法

function AnotherSingleton (name,age) {
  this.name = name;
  this.age = age;
  if(this.constructor.instance)
    return this.constructor.instance;
  this.constructor.instance = this;
}

let a = new AnotherSingleton('s', 1);
let b = new AnotherSingleton('k', 2);
Run Code Online (Sandbox Code Playgroud)

上述输出将是:

console.log(a.name, a.age, b.name, b.age) // s 1 s 1
Run Code Online (Sandbox Code Playgroud)


小智 7

皮肤猫的方法不止一种:根据您的品味或具体需要,您可以应用任何建议的解决方案.我个人尽可能地去找CMS的第一个解决方案(当你不需要隐私时).既然问题是关于最简单和最干净的,那就是胜利者.甚至:

var myInstance = {}; // done!
Run Code Online (Sandbox Code Playgroud)

这(引自我的博客)......

var SingletonClass = new function() { 
    this.myFunction() { 
        //do stuff 
    } 
    this.instance = 1; 
}
Run Code Online (Sandbox Code Playgroud)

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

var SingletonClass = { 
    myFunction: function () { 
        //do stuff 
    },
    instance: 1 
}
Run Code Online (Sandbox Code Playgroud)


ska*_*lee 7

我弃用了我的答案,看到我的另一个.

通常模块模式(参见CMS的答案)不是单例模式就足够了.然而,单例的一个特征是它的初始化被延迟直到需要对象.模块模式缺少此功能.

我的主张(CoffeeScript):

window.singleton = (initializer) ->
  instance = undefined
  () ->
    return instance unless instance is undefined
    instance = initializer()
Run Code Online (Sandbox Code Playgroud)

在JavaScript中编译为:

window.singleton = function(initializer) {
    var instance;
    instance = void 0;
    return function() {
        if (instance !== void 0) {
            return instance;
        }
        return instance = initializer();
    };
};
Run Code Online (Sandbox Code Playgroud)

然后我可以做以下事情:

window.iAmSingleton = singleton(function() {
    /* This function should create and initialize singleton. */
    alert("creating");
    return {property1: 'value1', property2: 'value2'};
});


alert(window.iAmSingleton().property2); // "creating" will pop up; then "value2" will pop up
alert(window.iAmSingleton().property2); // "value2" will pop up but "creating" will not
window.iAmSingleton().property2 = 'new value';
alert(window.iAmSingleton().property2); // "new value" will pop up
Run Code Online (Sandbox Code Playgroud)


Wol*_*ahl 7

对我来说,最简单/最干净的方式也意味着简单地理解,没有像 Java 版本的讨论中所讨论的那样花哨的东西:

在 Java 中实现单例模式的有效方法是什么?

从我的角度来看,最适合最简单/最干净的答案是:

乔纳森对在 Java 中实现单例模式的有效方法是什么的回答

并且它只能部分转换为 JavaScript。JavaScript 的一些不同之处在于:

  • 构造函数不能是私有的
  • 类不能有声明的字段

但考虑到最新的 ECMA 语法,有可能接近:

单例模式作为 JavaScript 类示例

 class Singleton {

  constructor(field1,field2) {
    this.field1=field1;
    this.field2=field2;
    Singleton.instance=this;
  }

  static getInstance() {
    if (!Singleton.instance) {
      Singleton.instance=new Singleton('DefaultField1','DefaultField2');
    }
    return Singleton.instance;
  }
}
Run Code Online (Sandbox Code Playgroud)

示例用法

console.log(Singleton.getInstance().field1);
console.log(Singleton.getInstance().field2);
Run Code Online (Sandbox Code Playgroud)

示例结果

DefaultField1
DefaultField2
Run Code Online (Sandbox Code Playgroud)


Jam*_*mes 7

使用 ES6 类和私有静态字段。调用 Singleton 类的新实例将返回相同的实例。实例变量也是私有的,不能在类外部访问。

class Singleton {
  // # is a new Javascript feature that denotes private
  static #instance;

  constructor() {
    if (!Singleton.#instance) {
      Singleton.#instance = this
    } 
    return Singleton.#instance
  }

  get() {
    return Singleton.#instance;
  }
}

const a = new Singleton();
const b = new Singleton();
console.log(a.get() === b.get()) // true
console.log(Singleton.instance === undefined) // true
Run Code Online (Sandbox Code Playgroud)


ska*_*lee 6

简短回答:

因为JavaScript的非阻塞性,JavaScript中的Singletons在使用中真的很难看.全局变量在没有所有这些回调的情况下也会通过整个应用程序为您提供一个实例,模块模式轻轻地隐藏在接口后面的内部.见@CMS答案.

但是,既然你想要一个单身......

var singleton = function(initializer) {

  var state = 'initial';
  var instance;
  var queue = [];

  var instanceReady = function(createdInstance) {
    state = 'ready';
    instance = createdInstance;
    while (callback = queue.shift()) {
      callback(instance);
    }
  };

  return function(callback) {
    if (state === 'initial') {
      state = 'waiting';
      queue.push(callback);
      initializer(instanceReady);
    } else if (state === 'waiting') {
      queue.push(callback);
    } else {
      callback(instance);
    }
  };

};
Run Code Online (Sandbox Code Playgroud)

用法:

var singletonInitializer = function(instanceReady) {
  var preparedObject = {property: 'value'};
  // calling instanceReady notifies singleton that instance is ready to use
  instanceReady(preparedObject);
}
var s = singleton(singletonInitializer);

// get instance and use it
s(function(instance) {
  instance.doSomething();
});
Run Code Online (Sandbox Code Playgroud)

说明:

单身人士通过整个应用程序为您提供的不仅仅是一个实例:他们的初始化被推迟到第一次使用.当你处理初始化很昂贵的对象时,这真的很重要.昂贵通常意味着I/O和JavaScript I/O总是意味着回调.

不要相信给你界面的答案instance = singleton.getInstance(),他们都错过了重点.

如果他们在实例准备就绪时不进行回调,那么当初始化程序执行I/O时它们将无法工作.

是的,回调总是比函数调用看起来更丑,它立即返回对象实例.但同样:当你做I/O时,回调是强制性的.如果你不想做任何I/O,那么实例化在程序启动时就足够便宜了.

例1,廉价的初始化程序:

var simpleInitializer = function(instanceReady) {
  console.log("Initializer started");
  instanceReady({property: "initial value"});
}

var simple = singleton(simpleInitializer);

console.log("Tests started. Singleton instance should not be initalized yet.");

simple(function(inst) {
  console.log("Access 1");
  console.log("Current property value: " + inst.property);
  console.log("Let's reassign this property");
  inst.property = "new value";
});
simple(function(inst) {
  console.log("Access 2");
  console.log("Current property value: " + inst.property);
});
Run Code Online (Sandbox Code Playgroud)

例2,使用I/O进行初始化:

在这个例子中setTimeout伪造了一些昂贵的I/O操作.这说明了为什么JavaScript中的单例真的需要回调.

var heavyInitializer = function(instanceReady) {
  console.log("Initializer started");
  var onTimeout = function() {
    console.log("Initializer did his heavy work");
    instanceReady({property: "initial value"});
  };
  setTimeout(onTimeout, 500);
};

var heavy = singleton(heavyInitializer);

console.log("In this example we will be trying");
console.log("to access singleton twice before it finishes initialization.");

heavy(function(inst) {
  console.log("Access 1");
  console.log("Current property value: " + inst.property);
  console.log("Let's reassign this property");
  inst.property = "new value";
});

heavy(function(inst) {
  console.log("Access 2. You can see callbacks order is preserved.");
  console.log("Current property value: " + inst.property);
});

console.log("We made it to the end of the file. Instance is not ready yet.");
Run Code Online (Sandbox Code Playgroud)


Kha*_*lla 6

我从JavaScript模型中获得了这个例子使用编码和设计模式构建更好的应用程序通过Stoyan Stefanov的书,如果你需要一些简单的实现类,如singltone对象,你可以使用立即函数如下:

var ClassName;

(function() {
    var instance;
    ClassName = function ClassName() {
        //If private instance variable already initialized return reference
        if(instance) {
            return instance;   
        }
        //If instance does not created save pointer of original reference
        //to private instance variable. 
        instance = this;

        //All constructor initialization will be here
        // i.e.: 
        this.someProperty = 0;
        this.someMethod = function() {
            //Some action here
        };
    };
}());
Run Code Online (Sandbox Code Playgroud)

您可以通过以下测试用例来检查此示例:

//Extending defined class like Singltone object using new prototype property
ClassName.prototype.nothing = true;
var obj_1 = new ClassName();
//Extending defined class like Singltone object using new prototype property
ClassName.prototype.everything = true; 
var obj_2 = new ClassName();

//Testing does this two object pointing to same instance
console.log(obj_1 === obj_2); //Result is true, it points to same instance object

//All prototype properites work
//no matter when they were defined
console.log(obj_1.nothing && obj_1.everything 
            && obj_2.nothing && obj_2.everything); //Result true


//Values of properties which is defined inside of constructor
console.log(obj_1.someProperty);// output 0
console.log(obj_2.someProperty);// output 0 
//Changing property value 
obj_1.someProperty = 1;

console.log(obj_1.someProperty);// output 1
console.log(obj_2.someProperty);// output 1

console.log(obj_1.constructor === ClassName); //Output true 
Run Code Online (Sandbox Code Playgroud)

这种方法传递所有测试用例,而私有静态实现将在使用原型扩展时失败(可以修复但不简单),并且由于实例暴露给公众,公共静态实现不太可取.

jsFiddly演示.


小智 6

以下在节点v6中起作用

class Foo {
  constructor(msg) {

    if (Foo.singleton) {
      return Foo.singleton;
    }

    this.msg = msg;
    Foo.singleton = this;
    return Foo.singleton;
  }
}
Run Code Online (Sandbox Code Playgroud)

我们测试:

const f = new Foo('blah');
const d = new Foo('nope');
console.log(f); // => Foo { msg: 'blah' }
console.log(d); // => Foo { msg: 'blah' }
Run Code Online (Sandbox Code Playgroud)


tal*_*nes 5

Christian C. SalvadózzzzBov 的回答都给出了很好的答案,但只是基于我从 PHP/Zend Framework 进入重度 Node.js 开发的基础上添加我自己的解释,其中单例模式很常见。

以下注释记录代码基于以下要求:

  • 一个且只有一个函数对象实例可以被实例化
  • 该实例不是公开可用的,只能通过公共方法访问
  • 构造函数不是公开可用的,只有在没有可用的实例时才可以实例化
  • 构造函数的声明必须允许修改其原型链。这将允许构造函数从其他原型继承,并为实例提供“公共”方法

我的代码与 zzzzBov 的答案非常相似,除了我在构造函数中添加了一个原型链和更多注释,这些注释应该可以帮助那些来自 PHP 或类似语言的人将传统的 OOP 转换为 JavaScript 的原型性质。它可能不是“最简单”的,但我相信它是最合适的。

// Declare 'Singleton' as the returned value of a self-executing anonymous function
var Singleton = (function () {
    "use strict";
    // 'instance' and 'constructor' should not be available in a "public" scope
    // here they are "private", thus available only within
    // the scope of the self-executing anonymous function
    var _instance=null;
    var _constructor = function (name) {
        this.name = name || 'default';
    }

    // Prototypes will be "public" methods available from the instance
    _constructor.prototype.getName = function () {
        return this.name;
    }

    // Using the module pattern, return a static object
    // which essentially is a list of "public static" methods
    return {
        // Because getInstance is defined within the same scope
        // it can access the "private" 'instance' and 'constructor' vars
        getInstance:function (name) {
            if (!_instance) {
                console.log('creating'); // This should only happen once
                _instance = new _constructor(name);
            }
            console.log('returning');
            return _instance;
        }
    }

})(); // Self execute

// Ensure 'instance' and 'constructor' are unavailable
// outside the scope in which they were defined
// thus making them "private" and not "public"
console.log(typeof _instance); // undefined
console.log(typeof _constructor); // undefined

// Assign instance to two different variables
var a = Singleton.getInstance('first');
var b = Singleton.getInstance('second'); // passing a name here does nothing because the single instance was already instantiated

// Ensure 'a' and 'b' are truly equal
console.log(a === b); // true

console.log(a.getName()); // "first"
console.log(b.getName()); // Also returns "first" because it's the same instance as 'a'
Run Code Online (Sandbox Code Playgroud)

请注意,从技术上讲,自执行匿名函数本身就是一个单例,正如 Christian C. Salvadó 提供的代码中所展示的那样。这里唯一的问题是,当构造函数本身是匿名的时,不可能修改构造函数的原型链。

请记住,对于 JavaScript,“公共”和“私有”的概念不像在 PHP 或 Java 中那样适用。但是我们通过利用 JavaScript 的功能范围可用性规则实现了相同的效果。


Der*_*ang 5

你可以这样做:

var singleton = new (function() {
  var bar = 123

  this.foo = function() {
    // Whatever
  }
})()
Run Code Online (Sandbox Code Playgroud)


Dav*_*vid 5

我想我找到了最简洁的JavaScript编程方式,但你需要一些想象力.我从"javascript the good parts"一书中的一种工作技术中得到了这个想法.

您可以创建一个这样的类,而不是使用new关键字:

function Class()
{
    var obj = {}; // Could also be used for inheritence if you don't start with an empty object.

    var privateVar;
    obj.publicVar;

    obj.publicMethod= publicMethod;
    function publicMethod(){} 

    function privateMethod(){} 

    return obj;
}
Run Code Online (Sandbox Code Playgroud)

您可以通过以下方式实例化上述对象:

var objInst = Class(); // !!! NO NEW KEYWORD
Run Code Online (Sandbox Code Playgroud)

现在考虑到这种工作方法,你可以创建一个像这样的单例:

ClassSingleton = function()
{
    var instance= null;

    function Class() // This is the class like the above one
    {
        var obj = {};
        return obj;
    }

    function getInstance()
    {
        if( !instance )
            instance = Class(); // Again no new keyword;

        return instance;
    }   

    return { getInstance : getInstance };

}();
Run Code Online (Sandbox Code Playgroud)

现在您可以通过调用获取您的实例

var obj = ClassSingleton.getInstance();
Run Code Online (Sandbox Code Playgroud)

我认为这是最好的方式,因为完整的"类"甚至无法访问.


令狐葱*_*令狐葱 5

最清楚的答案应该是 Addy Osmani 所著的《学习 JavaScript 设计模式》一书中的这个答案。

var mySingleton = (function () {

  // Instance stores a reference to the singleton
  var instance;

  function init() {

    // Singleton

    // Private methods and variables
    function privateMethod(){
        console.log( "I am private" );
    }

    var privateVariable = "I'm also private";

    var privateRandomNumber = Math.random();

    return {

      // Public methods and variables
      publicMethod: function () {
        console.log( "The public can see me!" );
      },

      publicProperty: "I am also public",

      getRandomNumber: function() {
        return privateRandomNumber;
      }

    };

  };

  return {

    // Get the singleton instance if one exists
    // or create one if it doesn't
    getInstance: function () {

      if ( !instance ) {
        instance = init();
      }

      return instance;
    }

  };

})();
Run Code Online (Sandbox Code Playgroud)


Ara*_*chi 5

这就是我使用 ES6 功能实现单例模式的方法。是的,我知道这看起来不像面向对象的方法,但我发现这种方法很容易实现,而且是一种干净的实现方式。

const Singleton = (() => {
  var _instance = !_instance && new Object('Object created....');
  return () => _instance;
})();

//************************************************************************

var instance1 = Singleton();
var instance2 = Singleton();
console.log(instance1 === instance2); // true
Run Code Online (Sandbox Code Playgroud)