web-dev-qa-db-fra.com

Conversion d'objets JS singleton pour utiliser des classes ES6

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

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;
38
Brian Genisio

Non. Ça n'a aucun sens.

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

67
Jason Sebring

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)

11
AdrianD

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 )

> Si je comprends correctement CommonJS + les implémentations du navigateur, la sortie d'un module est mise en cache, donc exporter la nouvelle MyClass () par défaut entraînera quelque chose qui se comportera comme un singleton (une seule> instance de cette classe existera jamais par processus/client en fonction de> env qui s'exécute).

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

5
Milan Karunarathne