Преобразование объектов SingleSt JS для использования классов ES6
Я использую ES6 с Webpack es6-transpiler в моей статье здесь: http://www.railsonmaui.com/blog/2014/10/02/integrating-webpack-and-the-es6-transpiler-into-an-existing-rails-project/
Есть ли смысл конвертировать два объекта Singleton для использования классов ES6?
import { CHANGE_EVENT } from "../constants/Constants";
var EventEmitter = require('events').EventEmitter;
var merge = require('react/lib/merge');
var _flash = null;
var BaseStore = merge(EventEmitter.prototype, {
emitChange: function() {
this.emit(CHANGE_EVENT);
},
/**
* @param {function} callback
*/
addChangeListener: function(callback) {
this.on(CHANGE_EVENT, callback);
},
/**
* @param {function} callback
*/
removeChangeListener: function(callback) {
this.removeListener(CHANGE_EVENT, callback);
},
getFlash: function() {
return _flash;
},
setFlash: function(flash) {
_flash = flash;
}
});
export { BaseStore };
Это файл ManagerProducts.jsx, который имеет один синглтон, который должен простираться от BaseStore.
/**
* Client side store of the manager_product resource
*/
import { BaseStore } from "./BaseStore";
import { AppDispatcher } from '../dispatcher/AppDispatcher';
import { ActionTypes } from '../constants/Constants';
import { WebAPIUtils } from '../utils/WebAPIUtils';
import { Util } from "../utils/Util";
var merge = require('react/lib/merge');
var _managerProducts = [];
var receiveAllDataError = function(action) {
console.log("receiveAllDataError %j", action);
WebAPIUtils.logAjaxError(action.xhr, action.status, action.err);
};
var ManagerProductStore = merge(BaseStore, {
getAll: function() {
return _managerProducts;
}
});
var receiveAllDataSuccess = function(action) {
_managerProducts = action.data.managerProducts;
//ManagerProductStore.setFlash({ message: "Manager Product data loaded"});
};
ManagerProductStore.dispatchToken = AppDispatcher.register(function(payload) {
var action = payload.action;
if (Util.blank(action.type)) { throw `Invalid action, payload ${JSON.stringify(payload)}`; }
switch(action.type) {
case ActionTypes.RECEIVE_ALL_DATA_SUCCESS:
receiveAllDataSuccess(action);
break;
case ActionTypes.RECEIVE_ALL_DATA_ERROR:
receiveAllDataError(action);
break;
default:
return true;
}
ManagerProductStore.emitChange();
return true;
});
export { ManagerProductStore };
Ответы
Ответ 1
Я бы сказал, что одиночные игры (классы, которые управляют своим собственным временем жизни) не нужны ни на одном языке. Это не означает, что одноэлементное время жизни не полезно, просто я предпочитаю, чтобы что-то, кроме класса, управляло временем жизни объекта, например, контейнера DI.
При этом одноэлементный шаблон CAN может применяться к классам JavaScript, заимствуя шаблон "SingletonEnforcer", который использовался в ActionScript. Я вижу, что хочу сделать что-то подобное при переносе существующей базы кода, которая использует синглтоны в ES6.
В этом случае идея состоит в том, что вы делаете статический экземпляр singleton
с приватным (через un выставленный Symbol) с открытым статическим instance
getter. Затем вы ограничиваете конструктор тем, что имеет доступ к специальному символу singletonEnforcer
, который не отображается вне модуля. Таким образом, конструктор терпит неудачу, если кто-то, кроме синглтона, попытается "обновить" его. Он будет выглядеть примерно так:
const singleton = Symbol();
const singletonEnforcer = Symbol()
class SingletonTest {
constructor(enforcer) {
if(enforcer != singletonEnforcer) throw "Cannot construct singleton";
}
static get instance() {
if(!this[singleton]) {
this[singleton] = new SingletonTest(singletonEnforcer);
}
return this[singleton];
}
}
export default SingletonTest
Затем вы можете использовать его, как и любой другой синглтон:
import SingletonTest from 'singleton-test';
const instance = SingletonTest.instance;
Ответ 2
Нет. Не имеет смысла.
Вот действительно простой пример одиночного объекта в es6:
let appState = {};
export default appState;
Я использую этот подход в своем коде для общего состояния через модули. Не знаете, почему вы должны преобразовать его в класс только потому, что? Одиночный по его определению статически используется. Наличие того, чтобы код не использовать класс в качестве экземпляра класса, должен быть большим ключом, чтобы этого не делать.
Синглеты очень полезны для управления состоянием или когда экземпляры не имеют смысла использовать какую-либо библиотеку утилиты. Я не вижу причин не использовать их, если это необходимо.
Это крошечный пример того, как программисты стремятся к тому, чтобы сконструировать или масштабировать все до своего даже необходимого, и это огромная проблема в моем опыте, в результате чего проекты заканчиваются в некоторых случаях из-за отсутствия производительности. Потратьте свое время на приложение, а не на интеллектуальный рывок.
Ответ 3
Я должен был сделать то же самое, поэтому вот простой и прямой способ сделать синглтон,
curtsy to http://amanvirk.me/singleton-classes-in-es6/
let instance = null;
class Cache{
constructor() {
if(!instance){
instance = this;
}
// to test whether we have singleton or not
this.time = new Date()
return instance;
}
}
let cache = new Cache()
console.log(cache.time);
setTimeout(function(){
let cache = new Cache();
console.log(cache.time);
},4000);
Оба вызова console.log
должны печатать один и тот же cache.time
(Singleton)
Ответ 4
Чтобы создать шаблон Singleton, используйте один экземпляр с классами ES6;
'use strict';
import EventEmitter from 'events';
class Single extends EventEmitter {
constructor() {
this.state = {};
}
getState() {
return this.state;
}
}
export default let single = new Single();
Обновить. Согласно объяснению @Bergi, ниже один не является допустимым аргументом.
Это работает из-за (см. Steven)
> Если я правильно понимаю реализации CommonJS + в браузере, > вывод модуля кэшируется, поэтому экспорт по умолчанию нового MyClass() будет > привести к чему-то, что ведет себя как одиночный (только один > экземпляр этого класса будет когда-либо существовать на процесс/клиент в зависимости от > env он работает).
Дел > Здесь вы можете найти пример ES6 Singleton.
Примечание: этот шаблон используется в Flux Dispacher
Flux: www.npmjs.com/package/flux
Пример Dispacher: github.com/facebook/flux/blob/master/examples/flux-todomvc/js/dispatcher/AppDispatcher.js#L16
Ответ 5
Альтернативный ответ
Классы ES6 поддерживают "статическое" ключевое слово, поэтому, по существу, вы можете создать класс и по самому его определению, используя статические члены, чтобы он имел возможности singleton по дизайну.
class MyClass {
static instanceCount = 0;
constructor() {
MyClass.instanceCount++;
}
static getInstanceCount() {
// "this" refers to static members when used within a static method
return this.instanceCount;
}
}
Таким образом вы получаете все функциональные возможности класса. Вы можете хранить глобальные данные внутри них другими словами, но более структурированным способом.