J'utilise ES6 avec le Webpack es6-transpiler par mon article ici: http://www.railsonmaui.com/blog/2014/10/02/integrating-webpack-and-the-es6-transpiler- dans un projet Rails existant /
Est-il judicieux de convertir deux objets Singleton pour utiliser des classes 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 };
Il s'agit du fichier ManagerProducts.jsx qui a un singleton qui doit s'étendre à partir de 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 };
Je dirais que les singletons (classes qui gèrent leur propre durée de vie singleton) ne sont pas nécessaires dans n'importe quelle langue. Cela ne veut pas dire que la durée de vie singleton n'est pas utile, juste que je préfère que quelque chose d'autre que la classe gère la durée de vie d'un objet, comme un conteneur DI.
Cela étant dit, le modèle singleton PEUT être appliqué aux classes JavaScript, empruntant le modèle "SingletonEnforcer" utilisé dans ActionScript. Je peux voir vouloir faire quelque chose comme ça lors du portage d'une base de code existante qui utilise des singletons dans ES6.
Dans ce cas, l'idée est que vous créez une instance privée (via un symbole non exposé) statique singleton
, avec un getter public statique instance
. Vous limitez ensuite le constructeur à quelque chose qui a accès à un symbole singletonEnforcer
spécial qui n'est pas exposé à l'extérieur du module. De cette façon, le constructeur échoue si quelqu'un d'autre que le singleton essaie de le "nouveau". Cela ressemblerait à quelque chose comme ceci:
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
Ensuite, vous pouvez l'utiliser comme n'importe quel autre singleton:
import SingletonTest from 'singleton-test';
const instance = SingletonTest.instance;
Voici un exemple très simple d'un objet singleton dans es6:
let appState = {};
export default appState;
Si vous voulez vraiment utiliser une classe dans votre approche singleton, je vous déconseille d'utiliser "statique" car c'est plus déroutant que bon pour un singleton au moins pour JS et retournez plutôt l'instance de la classe comme singleton comme ça ...
class SomeClassUsedOnlyAsASingleton {
// implementation
}
export default new SomeClassUsedOnlyAsASingleton();
De cette façon, vous pouvez toujours utiliser toutes les choses que vous aimez que JavaScript offre, mais cela réduira la confusion car les statiques IMO ne sont de toute façon pas entièrement prises en charge dans les classes JavaScript comme dans les langages typés tels que c # ou Java car il ne prend en charge que les méthodes statiques, sauf si vous les simulez et les attachez directement à une classe (au moment d'écrire ces lignes).
J'ai dû faire la même chose alors voici une façon simple et directe de faire un singleton, en faisant la révérence pour singleton-classes-in-es6
(lien d'origine 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);
Tous les deux console.log
les appels doivent imprimer le même cache.time
(Singleton)
Afin de créer un motif Singleton utiliser une seule instance avec les classes ES6;
'use strict';
import EventEmitter from 'events';
class Single extends EventEmitter {
constructor() {
this.state = {};
}
getState() {
return this.state;
}
}
export default let single = new Single();
Mise à jour : Selon l'explication @Bergi, en dessous de un n'est pas un argument valide.
Cela fonctionne à cause de (voir Steven )
Vous pouvez trouver un exemple ici ES6 Singleton .
Remarque : Ce modèle utilise dans Flux Dispacher
Flux : www.npmjs.com/package/flux
Exemple de répartiteur : github.com/facebook/flux/blob/master/examples/flux-todomvc/js/dispatcher/AppDispatcher.js # L16