Какой самый простой / чистый способ реализовать шаблон синглтона в JavaScript?
Какой самый простой / чистый способ реализовать шаблон синглтона в JavaScript?
Ответы:
Я думаю, что самый простой способ - объявить простой объектный литерал:
var myInstance = {
method1: function () {
// ...
},
method2: function () {
// ...
}
};
Если вы хотите, чтобы в вашем экземпляре синглтона были приватные участники, вы можете сделать что-то вроде этого:
var myInstance = (function() {
var privateVar = '';
function privateMethod () {
// ...
}
return { // public interface
publicMethod1: function () {
// all private members are accessible here
},
publicMethod2: function () {
}
};
})();
Это было названо в шаблон модуля , это в принципе позволяет инкапсулировать частных пользователей на объекте, воспользовавшись использованием затворов .
ОБНОВЛЕНИЕ: Я хотел бы добавить, что если вы хотите предотвратить модификацию одноэлементного объекта, вы можете заморозить его , используя Object.freeze
метод ES5 .
Это сделает объект неизменным, предотвращая любые изменения его структуры и значений.
Кроме того, я хотел бы отметить, что если вы используете ES6, вы можете очень легко представлять одиночный файл с помощью модулей ES , и вы даже можете хранить приватное состояние , объявив переменные в области видимости модуля :
// my-singleton.js
const somePrivateState = []
function privateFn () {
// ...
}
export default {
method1() {
// ...
},
method2() {
// ...
}
}
Затем вы можете просто импортировать объект singleton, чтобы использовать его:
import myInstance from './my-singleton.js'
// ...
publicMethod1
позвонить publicMethod2
?
getInstance
метод и закрытый конструктор, но IMO, это самый «простой» способ создания одноэлементного объекта. в Javascript, и в конце он встречает ту же цель - единственный объект, который вы не можете инициализировать снова (нет конструктора, это просто объект) -. О коде вы связаны, у него есть какие - то проблемы, поменять местами a
и b
объявления переменных и тест a === window
. Приветствия.
Я думаю, что самый чистый подход - это что-то вроде:
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();
delete instance.constructor
:x = SingletonClass.getInstance();delete x.constructor;new x.constructor;
Я не уверен, что согласен с шаблоном модуля, который используется в качестве замены одноэлементного шаблона. Я часто видел синглтоны, которые использовались и злоупотребляли в местах, где они совершенно не нужны, и я уверен, что шаблон модуля заполняет много пробелов, где программисты иначе использовали бы синглтон, однако шаблон модуля не является синглтоном.
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;
}());
В обеих версиях шаблона 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
var singleton = {}
не подходит под это определение.
var singleton = {}
Вот как вы реализуете синглтон в Javascript .
В 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
instance
поле. Поскольку он в данный момент ( instance
установлен this
), этот класс может иметь и другие поля, и заморозка не имеет смысла.
Следующие работы в узле 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' }
В 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"
instance
и _instance
. Это просто соглашение об именах в языках программирования, в котором мы называем частные переменные с добавлением подчеркивания. Я подозреваю, что причина вашего кода не работает в том, что вы используете this.instance
вместоMyClass.instance
Существует более одного способа кожи кошки :) В зависимости от вашего вкуса или конкретной потребности вы можете применить любое из предложенных решений. Лично я по возможности выбираю первое решение CMS (когда вам не нужна конфиденциальность). Поскольку вопрос был о самом простом и чистом, это победитель. Или даже:
var myInstance = {}; // done!
Это (цитата из моего блога) ...
var SingletonClass = new function() {
this.myFunction() {
//do stuff
}
this.instance = 1;
}
не имеет особого смысла (пример моего блога тоже не имеет), потому что ему не нужны частные переменные, так что это почти так же, как:
var SingletonClass = {
myFunction: function () {
//do stuff
},
instance: 1
}
this.f(){}
Я не одобряю мой ответ, см. Мой другой .
Обычно шаблон модуля (см. Ответ CMS), который НЕ является одноэлементным, достаточно хорош. Однако одной из особенностей singleton является то, что его инициализация задерживается до тех пор, пока объект не понадобится. В шаблоне модуля отсутствует эта функция.
Мое предложение (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
Поскольку неблокирующая природа JavaScript, Singletons в JavaScript действительно ужасны в использовании. Глобальные переменные также дадут вам один экземпляр для всего приложения без всех этих обратных вызовов, шаблон модуля мягко скрывает внутренние компоненты за интерфейсом. Смотрите ответ @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();
});
Синглтоны дают вам более одного экземпляра для всего приложения: их инициализация задерживается до первого использования. Это действительно большая вещь, когда вы имеете дело с объектами, инициализация которых стоит дорого. Дорогой обычно означает ввод / вывод, а в JavaScript ввод / вывод всегда означает обратный вызов.
Не верьте ответам, которые дают вам интерфейс, как instance = singleton.getInstance()
они все упускают суть.
Если они не принимают обратный вызов для запуска, когда экземпляр готов, то они не будут работать, когда инициализатор выполняет ввод-вывод.
Да, обратные вызовы всегда выглядят хуже, чем вызов функции, которая немедленно возвращает экземпляр объекта. Но опять же: когда вы делаете ввод / вывод, обратные вызовы обязательны. Если вы не хотите выполнять какие-либо операции ввода-вывода, то создание экземпляра достаточно дешево, чтобы сделать это при запуске программы.
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);
});
В этом примере setTimeout
подделка некоторых дорогостоящих операций ввода-вывода. Это показывает, почему синглтонам в 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.");
Я получил этот пример из JavaScript Patterns. Создайте лучшие приложения с помощью шаблонов кодирования и дизайна. По книге Стояна Стефанова, если вам нужен какой-то простой класс реализации, такой как объект 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
Этот подход пропускает все тестовые случаи, в то время как частная статическая реализация завершится неудачно, когда используется расширение прототипа (оно может быть исправлено, но не будет простым), и публичная статическая реализация менее желательна из-за того, что экземпляр открыт для публики.
Я думаю, что нашел самый чистый способ программирования на JavaScript, но вам нужно немного воображения. Я получил эту идею из техники работы в книге "Javascript хорошие части".
Вместо использования нового ключевого слова вы можете создать класс, подобный этому:
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();
Я думаю, что это самый удачный способ, так как полный «Класс» даже недоступен.
@CMS и @zzzzBov оба дали замечательные ответы, но просто добавили мою собственную интерпретацию, основанную на том, что я перешел в разработку heavy node.js из PHP / Zend Framework, где синглтон-шаблоны были распространены.
Следующий документированный код основан на следующих требованиях:
Мой код очень похож на код @ zzzzBov, за исключением того, что я добавил цепочку прототипов в конструктор и добавил больше комментариев, которые должны помочь тем, кто прибывает из PHP или аналогичного языка, переводить традиционный ООП в прототип 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'
Обратите внимание, что технически самоисполняющаяся анонимная функция сама по себе является синглтоном, что хорошо продемонстрировано в коде, предоставленном @CMS. Единственный улов здесь заключается в том, что невозможно изменить цепочку прототипов конструктора, когда сам конструктор является анонимным.
Помните, что в Javascript понятия «открытый» и «закрытый» не применяются, как в PHP или Java. Но мы достигли того же эффекта, используя правила доступности функциональных возможностей Javascript.
var a = Singleton.getInstance('foo'); var b = new a.constructor('bar');
Не знаю, почему никто не поднял это, но вы могли бы просто сделать:
var singleton = new (function() {
var bar = 123
this.foo = function() {
// whatever
}
})()
Самый ясный ответ должен быть этот из книги «Изучение шаблонов дизайна 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;
}
};
})();
Я считаю, что это самый простой / чистый и интуитивно понятный способ, хотя он требует ES7:
export default class Singleton { static instance; constructor(){ if(instance){ return instance; } this.state = "duke"; this.instance = this; } }
Исходный код от: adam-bien.com
new Singleton()
Могу ли я положить свои 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)
Я обнаружил, что следующее - это самый простой шаблон Singleton, потому что использование оператора new делает его сразу доступным внутри функции, устраняя необходимость возвращать литерал объекта:
var singleton = new (function () {
var private = "A private value";
this.printSomething = function() {
console.log(private);
}
})();
singleton.printSomething();
Вот простой пример для объяснения синглтон-паттерна в javascript.
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();
Мне нужно было несколько синглетонов с:
и вот что я придумал:
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, чтобы это работало, поэтому если у вас есть пустые переменные, просто передайте []
Я использовал оконный объект в функции, но мог бы передать параметр, чтобы создать собственную область видимости.
Параметры name и construct являются только String для работы window [], но с некоторой простой проверкой типов также возможны window.name и window.construct.
Как насчет этого, просто застраховать, класс не может снова новый.
Таким образом, вы можете использовать instanceof
опцию, также вы можете использовать цепочку прототипов для наследования класса, это обычный класс, но вы не можете его создать, если вы хотите получить экземпляр, просто используйте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
участника, просто поместите его в закрытие.
Ниже приведен фрагмент из моей прогулки по реализации шаблона синглтона. Это произошло со мной во время собеседования, и я почувствовал, что должен это где-то запечатлеть.
/*************************************************
* 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 странице
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
Вы можете сделать это с помощью декораторов, как в следующем примере для 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.
Также обратите внимание, что экземпляр singleton создается «ленивым», т. Е. Создается только при первом его использовании.
Шаблон модуля: в «более читаемом стиле». Вы можете легко увидеть, какие методы являются публичными, а какие приватными
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 (); // -> я вызываю приватный метод через оповещение о публичном методе («привет, я приватный метод»)
Синглтон:
Убедитесь, что у класса есть только один экземпляр, и предоставьте ему глобальную точку доступа.
Шаблон Singleton ограничивает количество экземпляров определенного объекта только одним. Этот единственный экземпляр называется синглтоном.
Объект Singleton реализован как непосредственная анонимная функция. Функция выполняется немедленно, заключив ее в квадратные скобки, за которыми следуют две дополнительные скобки. Он называется анонимным, потому что у него нет имени.
Образец программы,
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()
Simplest / Cleanest для меня означает также простое понимание и никаких наворотов, о чем много говорится в Java-версии обсуждения:
Каков эффективный способ реализации одноэлементного шаблона в Java?
Ответ, который подошел бы самым простым / чистым лучше всего с моей точки зрения:
https://stackoverflow.com/a/70824/1497139
И это может быть только частично переведено на JavaScript. Некоторые из различий в Javascript:
Но учитывая последний синтаксис ECMA, можно приблизиться к:
Шаблон Singleton как пример класса 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
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
Если вы хотите использовать классы:
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
Другой способ написания синглтона с использованием функции
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