Konwertowanie obiektów Singleton JS na klasy ES6

Używam ES6 z Webpack es6-transpiler na mój artykuł tutaj: http://www.railsonmaui.com/blog/2014/10/02/integrating-webpack-and-the-es6-transpiler-into-an-existing-rails-project/

Czy konwersja dwóch obiektów Singleton na klasy ES6 ma sens?

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

To jest file ManagerProducts.jsx, który ma singleton, który powinien rozciągać się od 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 };
Author: ProgramFOX, 2014-10-05

4 answers

Argumentowałbym, że singletony (klasy, które zarządzają własnym życiem Singletona) są niepotrzebne w każdym języku. Nie oznacza to, że singleton lifetime nie jest przydatny, tylko, że wolę, aby coś innego niż klasa zarządzała życiem obiektu, jak kontener DI.

To powiedziawszy, wzór Singletona może być stosowany do klas JavaScript, zapożyczając wzór "SingletonEnforcer", który został użyty w ActionScript. Widzę chęć zrobienia czegoś takiego, kiedy portowanie istniejącej bazy kodu używającej singletonów do ES6.

W tym przypadku idea polega na tym, że tworzy się prywatną (za pomocą nieeksponowanego symbolu) statyczną instancję singleton, z publicznym statycznym getterem instance. Następnie ograniczasz konstruktor do czegoś, co ma dostęp do specjalnego symbolu singletonEnforcer, który nie jest eksponowany poza modułem. W ten sposób konstruktor zawiedzie, jeśli ktoś inny niż singleton spróbuje go "zmienić". Wyglądałoby to mniej więcej tak:

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

Wtedy możesz używaj go jak każdy inny singleton:

import SingletonTest from 'singleton-test';
const instance = SingletonTest.instance;
 37
Author: Brian Genisio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-24 12:36:03

Nie. To nie ma sensu.

Oto bardzo prosty przykład obiektu singleton w es6:

let appState = {};
export default appState;

Jeśli naprawdę chcesz użyć klasy w podejściu singleton, zalecam, aby nie używać "static", ponieważ jest to bardziej mylące niż dobre dla Singletona przynajmniej dla JS i zamiast tego zwracać instancję klasy jako singleton jak tak...

class SomeClassUsedOnlyAsASingleton {
  // implementation
}

export default new SomeClassUsedOnlyAsASingleton();

W ten sposób możesz nadal używać wszystkich rzeczy klasowych, które lubisz, które oferuje JavaScript, ale zmniejszy to zamieszanie jako IMO static nie jest w pełni wspierany w klasach JavaScript, jak to jest w typowanych językach, takich jak c# lub Java, ponieważ obsługuje tylko statyczne metody, chyba że po prostu fałszujesz i dołączasz je bezpośrednio do klasy(w momencie pisania tego tekstu).

 67
Author: Jason Sebring,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-11 17:07:29

Musiałem zrobić to samo, więc oto prosty i bezpośredni sposób na wykonanie singletonu, do singleton-classes-in-es6

(oryginalny link 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);

Oba wywołania console.log powinny drukować to samo cache.time (Singleton)

 10
Author: AdrianD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-23 20:50:55

W celu stworzenia wzorca Singletona Użyj pojedynczej instancji z klasami ES6;

'use strict';

import EventEmitter from 'events';

class Single extends EventEmitter {
    constructor() {
        this.state = {};
    }

    getState() {
        return this.state;
    }

}

export default let single = new Single();

Update: zgodnie z wyjaśnieniem @ Bergi, poniżej jeden nie jest prawidłowym argumentem.

to działa z powodu (patrz Steven)

> Jeśli dobrze rozumiem implementacje CommonJS + przeglądarki, to > wyjście modułu jest buforowane, więc eksport domyślnej nowej MyClass () będzie > skutkować czymś, co zachowuje się jak singleton (tylko pojedynczy > instancja tej klasy będzie kiedykolwiek istniała dla procesu/klienta w zależności od > env to działa).

Przykład można znaleźć tutaj ES6 Singleton.

Uwaga : ten wzór jest używany w Flux Dispacher

Flux: www.npmjs.com/package/flux

Przykład Dispachera: github.com/facebook/flux/blob/master/examples/flux-todomvc/js/dispatcher/AppDispatcher.js#L16

 5
Author: Milan Karunarathne,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-18 13:59:47