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

时间:2009-09-25 20:05:52

标签: javascript function design-patterns singleton

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

39 个答案:

答案 0 :(得分:297)

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

var myInstance = {
  method1: function () {
    // ...
  },
  method2: function () {
    // ...
  }
};

如果你想在你的单例实例上使用私有成员,你可以这样做:

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

  function privateMethod () {
    // ...
  }

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

这被称为 module pattern ,它基本上允许您通过利用closures将私有成员封装在对象上。

更新:我想补充一点,如果您想阻止修改单件对象,可以使用ES5 Object.freeze 冻结方法

这将使对象不可变,从而阻止对其结构和值的任何修改。

此外,我想提一下,如果您使用的是ES6,您可以非常轻松地使用 ES模块代表单身人士,您甚至可以通过声明来保持私人状态 模块范围内的变量

// my-singleton.js
const somePrivateState = []

function privateFn () {
  // ...
}

export default {
  method1() {
    // ...
  },
  method2() {
    // ...
  }
}

然后你可以简单地导入单例对象来使用它:

import myInstance from './my-singleton.js'
// ...

答案 1 :(得分:160)

我认为最干净的方法是:

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;
        }
   };
})();

之后,您可以调用该函数

var test = SingletonFactory.getInstance();

答案 2 :(得分:96)

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

模块模式:

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();
}
long form,使用模块模式
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;
}());

在我提供的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

答案 3 :(得分:22)

在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

或者,如果您不希望在创建第二个实例时引发错误,则可以只返回最后一个实例,就像这样:

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"

答案 4 :(得分:12)

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

答案 5 :(得分:7)

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

var myInstance = {}; // done!

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

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

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

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

答案 6 :(得分:7)

我弃用了我的回答,请参阅my other one

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

我的主张(CoffeeScript):

window.singleton = (initializer) ->
  instance = undefined
  () ->
    return instance unless instance is undefined
    instance = initializer()

在JavaScript中编译为此内容:

window.singleton = function(initializer) {
    var instance;
    instance = void 0;
    return function() {
        if (instance !== void 0) {
            return instance;
        }
        return instance = initializer();
    };
};

然后我可以做以下事情:

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

答案 7 :(得分:6)

我从JavaScript Patterns Build Better Applications with Coding and Design Patterns By 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
        };
    };
}());

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

//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 

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

jsFiddly demo.

答案 8 :(得分: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;
}

您可以通过说:

来实例化上述对象
var objInst = Class(); // !!! NO NEW KEYWORD

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

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 };

}();

现在您可以通过调用

来获取您的实例
var obj = ClassSingleton.getInstance();

我认为这是最好的方式,因为完整的“班级”甚至无法访问。

答案 9 :(得分:5)

以下适用于节点v6

class Foo {
  constructor(msg) {

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

    this.msg = msg;
    Foo.singleton = this;
    return Foo.singleton;
  }
}

我们测试:

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

答案 10 :(得分:5)

简答:

因为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);
    }
  };

};

用法:

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();
});

说明:

Singletons在整个应用程序中为您提供的不仅仅是一个实例:它们的初始化会延迟到第一次使用。当你处理初始化很昂贵的对象时,这真的很重要。昂贵通常意味着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);
});

示例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.");

答案 11 :(得分:4)

不确定为什么没有人提起这件事,但你可以这么做:

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

  this.foo = function() {
    // whatever
  }
})()

答案 12 :(得分:4)

最明确的答案应该来自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 = "Im 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;
    }
 
  };
 
})();

答案 13 :(得分:4)

@CMS和@zzzzBov都给出了很好的答案,但只是根据我从PHP / Zend Framework开始进行繁重的node.js开发来添加我自己的解释,其中单例模式很常见。

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

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

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

// declare 'Singleton' as the returned value of a self-executing anonymous function
var Singleton = (function () {
    "use strict";
    // 'instance' and 'constructor' should not be availble 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'

请注意,从技术上讲,自执行匿名函数本身就是一个Singleton,在@CMS提供的代码中很好地证明了这一点。这里唯一的问题是,当构造函数本身是匿名的时,无法修改构造函数的原型链。

请记住,对于Javascript,“public”和“private”的概念不适用于PHP或Java。但是我们通过利用Javascript的功能范围可用性规则实现了相同的效果。

答案 14 :(得分:2)

我发现以下内容是最简单的Singleton模式,因为使用 new 运算符会使在函数中立即可用,从而无需返回对象文字:



var singleton = new (function () {

  var private = "A private value";
  
  this.printSomething = function() {
      console.log(private);
  }
})();

singleton.printSomething();




答案 15 :(得分:2)

以下是解释java脚本中单例模式的简单示例。

 var Singleton=(function(){
      var instance;
      var init=function(){
           return {
             display:function(){
             alert("This is a Singleton patern demo");
              }
            };
           }; 
            return {
              getInstance:function(){
                   if(!instance){
                     alert("Singleton check");
                      instance=init();
                       }
               return instance;
             }
         };

    })();

   // In this call first display alert("Singleton check")
  // and then alert("This is a Singleton patern demo");
  // It means one object is created

    var inst=Singleton.getInstance();
    inst.display();

    // In this call only display alert("This is a Singleton patern demo")
   //  it means second time new object is not created, 
   //  it uses the already created object 

    var inst1=Singleton.getInstance();
    inst1.display();

答案 16 :(得分:2)

我可以把我的5个硬币。我有一个构造函数,例如。

var A = function(arg1){
  this.arg1 = arg1  
};

我需要做的就是这个CF创建的每个对象都是一样的。

var X = function(){
  var instance = {};
  return function(){ return instance; }
}();

测试

var x1 = new X();
var x2 = new X();
console.log(x1 === x2)

答案 17 :(得分:2)

这有什么问题?

function Klass() {
   var instance = this;
   Klass = function () { return instance; }
}

答案 18 :(得分:2)

如果要使用类:

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);

以上内容的输出将是:

console.log(x.name,x.age,y.name,y.age) // s 1 s 1

使用函数编写Singleton的另一种方式

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);

以上内容的输出将是:

console.log(a.name,a.age,b.name,b.age)// s 1 s 1

答案 19 :(得分:1)

对我来说,最简单/最简洁的含义也只是简单地理解而已,而在Java版本的讨论中没有太多烦恼:

What is an efficient way to implement a singleton pattern in Java?

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

https://stackoverflow.com/a/70824/1497139

它只能部分翻译成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

答案 20 :(得分:1)

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, then pad zeroes to the codepoint
    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

答案 21 :(得分:1)

我需要几个单身人士:

  • lazy initialisation
  • 初始参数

所以这就是我想出来的:

createSingleton ('a', 'add', [1, 2]);
console.log(a);

function createSingleton (name, construct, args) {
    window[name] = {};
    window[construct].apply(window[name], args);
    window[construct] = null;
}

function add (a, b) {
    this.a = a;
    this.b = b;
    this.sum = a + b;
}
  • args必须是Array才能工作,所以如果你有空变量,那么 传入[]

  • 我在函数中使用了window对象,但我可以传入一个参数来创建自己的范围

  • name和construct参数只是window []的String,但是通过一些简单的类型检查,window.name和window.construct也是可以的。

答案 22 :(得分:1)

我相信这是最简单/最干净,最直观的方式,虽然它需要ES7:

export default class Singleton {

  static instance;

  constructor(){
    if(instance){
      return instance;
    }

    this.state = "duke";
    this.instance = this;
  }

}

源代码来自:adam-bien.com

答案 23 :(得分:1)

<强>的Singleton:

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

Singleton Pattern将特定对象的实例数限制为一个。这个单一实例称为单例。

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

Singleton对象实现为即时匿名函数。该函数立即执行,将其包装在括号中,然后再添加两个括号。它被称为匿名,因为它没有名称。

示例程序

&#13;
&#13;
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()
&#13;
&#13;
&#13;

答案 24 :(得分:1)

你可以使用下面针对TypeScript的示例中的装饰器来执行此操作:

class YourClass {

    @Singleton static singleton() {}

}

function Singleton(target, name, descriptor) {
    var instance;
    descriptor.value = () => {
        if(!instance) instance = new target;
        return instance;
    };
}

然后你就像这样使用你的单身:

var myInstance = YourClass.singleton();

在撰写本文时,装饰器在JavaScript引擎中并不容易获得。您需要确保您的JavaScript运行时实际启用了装饰器,或者使用像Babel和TypeScript这样的编译器。

另请注意,单例实例是“懒惰”创建的,即只有在您第一次使用它时才会创建它。

答案 25 :(得分:1)

这也不是单身人士吗?

function Singleton() {
    var i = 0;
    var self = this;

    this.doStuff = function () {
        i = i + 1;
        console.log( 'do stuff',i );
    };

    Singleton = function () { return self };
    return this;
}

s = Singleton();
s.doStuff();

答案 26 :(得分:1)

模块模式:“更具可读性”。你可以很容易地看到哪些方法是公开的,哪些方法是私有的

var module = (function(_name){
   /*Local Methods & Values*/
   var _local = {
      name : _name,
      flags : {
        init : false
      }
   }

   function init(){
     _local.flags.init = true;
   }

   function imaprivatemethod(){
     alert("hi im a private method");
   }

   /*Public Methods & variables*/

   var $r = {}; //this object will hold all public methods.

   $r.methdo1 = function(){
       console.log("method1 call it");
   }

   $r.method2 = function(){
      imaprivatemethod(); //calling private method
   }

   $r.init = function(){
      inti(); //making init public in case you want to init manually and not automatically
   }

   init(); //automatically calling init method

   return $r; //returning all publics methods

})("module");

现在您可以使用公共方法,例如

module.method2(); // - &GT;我正在通过公共方法警报调用私有方法(“我喜欢私人方法”)

http://jsfiddle.net/ncubica/xMwS9/

答案 27 :(得分:1)

这种方式怎么样,只是确保班级不能重新开始。

通过这个,你可以使用instanceof op,也可以使用原型链继承类,它是一个普通的类,但不能新建它,如果yuu想要获得实例只是使用getInstance

function CA()
{
    if(CA.instance)
    {
        throw new Error('can not new this class');
    }else{
        CA.instance = this;
    }

}
/**
 * @protected
 * @static
 * @type {CA}
 */
CA.instance = null;
/** @static */
CA.getInstance = function()
{
    return CA.instance;
}

CA.prototype = 
/** @lends CA#*/
{
    func: function(){console.log('the func');}
}
// initilize the instance
new CA();

// test here
var c = CA.getInstance()
c.func();
console.assert(c instanceof CA)
// this will failed
var b = new CA();

如果您不想公开instance成员,只需将其置于闭包中即可。

答案 28 :(得分:1)

以下是我演示实现单例模式的片段。在采访过程中我发生了这种情况,我觉得我应该把它捕捉到某个地方。

/*************************************************
   *     SINGLETON PATTERN IMPLEMENTATION          *
   *************************************************/

  //since there are no classes in javascript, every object is technically a singleton
  //if you don't inherit from it or copy from it.
  var single = {};
  //Singleton Implementations
  //Declaring as a Global Object...you are being judged!


  var Logger = function() {
    //global_log is/will be defined in GLOBAL scope here
    if(typeof global_log === 'undefined'){
      global_log = this;
    }
    return global_log;
  };


  //the below 'fix' solves the GLOABL variable problem but
  //the log_instance is publicly available and thus can be 

  //tampered with.
  function Logger() {
    if(typeof Logger.log_instance === 'undefined'){
      Logger.log_instance = this;
    }


    return Logger.log_instance;
   };


  //the correct way to do it to give it a closure!


  function logFactory() {
    var log_instance; //private instance
    var _initLog = function() { //private init method
      log_instance = 'initialized';
      console.log("logger initialized!")
    }
    return {
      getLog : function(){ //the 'privileged' method 
        if(typeof log_instance === 'undefined'){
          _initLog();
        }
        return log_instance;
      }
    };
  }

  /***** TEST CODE ************************************************
  //using the Logger singleton
  var logger = logFactory();//did i just gave LogFactory a closure?
  //create an instance of the logger
  var a = logger.getLog();
  //do some work
  //get another instance of the logger
  var b = logger.getLog();


  //check if the two logger instances are same?
  console.log(a === b); //true
  *******************************************************************/

同样可以在我的gist页面上找到

答案 29 :(得分:0)

Simple Example
    class Settings {
      constructor() {
        if (Settings.instance instanceof Settings) {
          return Settings.instance;
        }
        this.settings = {
          id: Math.floor(Math.random() * 4000),
          name: "background",
        };
        Object.freeze(this.settings);
        Object.freeze(this);
        Settings.instance = this;
      }
    }
    
    var o1 = new Settings();
    var o2 = new Settings();
    console.dir(o1);
    console.dir(o2);
    if (o1 === o2) {
      console.log("Matched");
    }

答案 30 :(得分:0)

let MySingleton = (function () {
  var _instance
  function init() {
    if(!_instance) {
      _instance = { $knew: 1 }
    }
    return _instance
  }
  let publicAPIs = {
    getInstance: function() {
      return init()
    }
  }
  // this prevents customize the MySingleton, like MySingleton.x = 1
  Object.freeze(publicAPIs) 
  // this prevents customize the MySingleton.getInstance(), like MySingleton.getInstance().x = 1
  Object.freeze(publicAPIs.getInstance())
  return publicAPIs
})();

答案 31 :(得分:0)

尚未提及我所知道的最干净的方法。它利用了类字段:

const singleton = new class {
    name = "foo";
    constructor() {
        console.log(`Singleton ${this.name} constructed`);
    }
}

使用这种语法,您可以确定自己的单身身份并将保持唯一性。

请注意,类字段需要节点v12 +或现代浏览器。

答案 32 :(得分:0)

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

答案 33 :(得分:0)

您可以在每个new执行中返回相同的实例-

function Singleton() {
    // lazy 
    if (Singleton.prototype.myInstance == undefined) {
        Singleton.prototype.myInstance = { description: "I am the instance"};
    }
    return Singleton.prototype.myInstance;
}

a = new Singleton();
b = new Singleton();
console.log(a); // { description: "I am the instance"};
console.log(b); // { description: "I am the instance"};
console.log(a==b); // true

答案 34 :(得分:0)

javascript中的Singleton是使用Module模式和闭包实现的。 下面的代码几乎是不言自明的 -

// singleton example.
var singleton = (function() {
  var instance;
  function init() {
    var privateVar1 = "this is a private variable";
    var privateVar2 = "another var";
    function pubMethod() {
      //accessing private variables from inside.
      console.log(this.privateVar1);
      console.log(this.privateVar2);
      console.log("inside of a public method");
    };
  }
  function getInstance() {
    if (!instance) {
      instance = init();
    }
    return instance;
  };
  return {
    getInstance: getInstance
  }
})();


var obj1 = singleton.getInstance();
var obj2 = singleton.getInstance();

cnosole.log(obj1===obj2); //check for type and value. 

答案 35 :(得分:0)

主要关键是对此后面的Undertand Closure重要性。甚至在内部函数内部的属性将在关闭的帮助下是私有的。

var Singleton = function(){      var instance;

 function init() {

    function privateMethod() {
        console.log("private via closure");
    }

    var privateVariable = "Private Property";

    var privateRandomNumber = Math.random();// this also private

    return {
        getRandomNumber: function () {  // access via getter in init call
            return privateRandomNumber;
        }

    };

};

return {
    getInstance: function () {

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

        return instance;
    }

};

};

答案 36 :(得分:0)

你没有在浏览器中说&#34;&#34;。否则,您可以使用NodeJS modules。这些are the same for each require call。基本示例:

  

foo.js的内容:

const circle = require('./circle.js');
console.log( `The area of a circle of radius 4 is ${circle.area(4)}`);
     

circle.js的内容:

const PI = Math.PI;

exports.area = (r) => PI * r * r;

exports.circumference = (r) => 2 * PI * r;

请注意,您无法访问circle.PI,因为它未导出。

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

答案 37 :(得分:0)

我喜欢使用Singleton与模块模式的组合,init-time分支与Global NS检查,包含在闭包中。在单例初始化之后环境不会改变的情况下;使用一个立即调用的object-literal来返回一个充满实用程序的模块,该模块将持续一段时间应该没问题。我没有传递任何依赖关系,只是在他们自己的小世界中调用单例 - 唯一的目标是:创建用于事件绑定/解除绑定的实用程序模块(在这种情况下,设备方向/方向更改也可以工作)。

window.onload = ( function( _w ) {
            console.log.apply( console, ['it', 'is', 'on'] );
            ( {
                globalNS : function() {
                    var nameSpaces = ["utils", "eventUtils"],
                        nsLength = nameSpaces.length,
                        possibleNS = null;

                    outerLoop:
                    for ( var i = 0; i < nsLength; i++ ) {
                        if ( !window[nameSpaces[i]] ) {
                            window[nameSpaces[i]] = this.utils;
                            break outerLoop;
                        };
                    };
                },
                utils : {
                    addListener : null,
                    removeListener : null
                },
                listenerTypes : {
                    addEvent : function( el, type, fn ) {
                        el.addEventListener( type, fn, false );
                    },
                    removeEvent : function( el, type, fn ) {
                        el.removeEventListener( type, fn, false );
                    },
                    attachEvent : function( el, type, fn ) {
                        el.attachEvent( 'on'+type, fn );
                    },
                    detatchEvent : function( el, type, fn ) {
                        el.detachEvent( 'on'+type, fn );
                    }
                },
                buildUtils : function() {
                    if ( typeof window.addEventListener === 'function' ) {
                        this.utils.addListener = this.listenerTypes.addEvent;
                        this.utils.removeListener = this.listenerTypes.removeEvent;
                    } else {
                        this.utils.attachEvent = this.listenerTypes.attachEvent;
                        this.utils.removeListener = this.listenerTypes.detatchEvent;
                    };
                    this.globalNS();
                },
                init : function() {
                    this.buildUtils();
                }
            } ).init();
        }( window ) );

答案 38 :(得分:-1)

var singlton= (function () {

    var singlton = function(){
       //do stuff
    }
    var instance = new singlton();
    return function(){
       return instance;
    }
})();

没有getInstance方法的解决方案