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


当前回答

你没说"在浏览器里"否则,你可以使用Node.js模块。这些对于每个require调用都是相同的。基本的例子:

foo.js的内容: Const circle = require('./circle.js'); console.log('半径为4的圆的面积为${circle.area(4)} '); circle.js的内容: const PI = Math.PI; 出口。area = (r) => PI * r * r; 出口。周长= (r) => 2 * PI * r;

注意,您不能访问圆。PI,因为它没有导出。

虽然这在浏览器中不起作用,但它简单而干净。

其他回答

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

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

Christian C. Salvadó和zzzzBov的回答都给出了精彩的答案,但只是添加我自己的解释,基于我已经从PHP/Zend框架转向了沉重的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'

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

请记住,在JavaScript中,“公共”和“私有”的概念并不像在PHP或Java中那样适用。但是,通过利用JavaScript的函数作用域可用性规则,我们也达到了同样的效果。

剥猫皮的方法不止一种:)根据你的口味或特定需求,你可以应用任何一种建议的解决方案。我个人倾向于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
}
function Once() {
    return this.constructor.instance || (this.constructor.instance = this);
}

function Application(name) {
    let app = Once.call(this);

    app.name = name;

    return app;
}

如果你在上课:

class Once {
    constructor() {
        return this.constructor.instance || (this.constructor.instance = this);
    }
}

class Application extends Once {
    constructor(name) {
        super();

        this.name = name;
    }
}

测试:

console.log(new Once() === new Once());

let app1 = new Application('Foobar');
let app2 = new Application('Barfoo');

console.log(app1 === app2);
console.log(app1.name); // Barfoo

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

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

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

Jonathan的回答是:在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;
  }
}

示例使用

console.log(Singleton.getInstance().field1);
console.log(Singleton.getInstance().field2);

例子的结果

DefaultField1
DefaultField2