2014-10-05 8 views
19

Я использую ES6 с WebPack ES6-transpiler на мою статью здесь: http://www.railsonmaui.com/blog/2014/10/02/integrating-webpack-and-the-es6-transpiler-into-an-existing-rails-project/Преобразование объектов Singleton JS использовать ES6 классы

Имеет ли смысл преобразовать два объектов 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.

+2

No. Если у вас есть одиночки, вам не нужен класс в JavaScript. Классы предназначены для построения нескольких экземпляров. – Bergi

+0

@bergi, вот что я понял. Но просто проверяю, есть ли что-то, чего я не вижу. – justingordon

ответ

32

Я бы сказал, что одиночные игры (классы, которые управляют своим временем жизни в одиночном режиме) не нужны ни на одном языке. Это не значит, что однолетнее время жизни не полезно, просто я предпочитаю, чтобы что-то, кроме класса, управляло временем жизни объекта, например, контейнера DI.

Как сказано, одноэлементный шаблон МОЖЕТ применяться к классам JavaScript, заимствуя шаблон «SingletonEnforcer», который использовался в ActionScript. Я вижу, что хочу сделать что-то подобное при переносе существующей базы кода, которая использует синглтоны в ES6.

В этом случае идея состоит в том, что вы делаете приватный (через un экспонированный символ) статический singleton экземпляр с открытым статическим instance геттером. Затем вы ограничиваете конструктор тем, что имеет доступ к специальному символу 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; 
+12

http://amanvirk.me/singleton-classes-in-es6/ лучше подходит, так как он управляет состоянием внутри самого конструктора –

+0

@AmanVirk Этот метод работает, если вы расширяете класс? –

+1

IMO немного странно, используя это в примере getter. Он не может ссылаться на сам класс, поскольку он является статическим методом. Я предпочел бы поставить '' ' const instance = null; '' ' вне класса, а затем использовать экземпляр в коде. Процессор все равно поместит все это в закрытие, поэтому в конце концов это будет закрытая переменная. Кроме того, это кажется хорошим решением! – dejakob

57

No. не имеет смысла.

Вот очень простой пример одноплодного объекта в ES6:

let appState = {}; 
export default appState; 

Если вы действительно хотите использовать класс в вашей одноплодной подходе, я бы рекомендовал не использовать «статический», поскольку это более запутанный, чем пользы для одноточечного по крайней мере, для JS и вместо вернуть экземпляр класса как синглтон как так ...

class SomeClassUsedOnlyAsASingleton { 
    // implementation 
} 

export default new SomeClassUsedOnlyAsASingleton(); 

таким образом, вы все еще можете использовать все классовые вещи, которые вы любите, что предложения JavaScript, но это приведет к сокращению путаница, поскольку статичность ИМО не полностью поддерживается в классах JavaScript, так или иначе, как на типизированных языках, таких как C# или Java, поскольку он поддерживает только статические методы, если вы просто не подделываете его и не присоединяете непосредственно к классу (на момент написания этой статьи).

+3

Или просто одна строка 'export default let appState = {};' :-) – Bergi

+0

@ Джейсон: Спасибо, вы действительно открыли мне глаза. Я также попытался определить одноэлементный класс, но иметь один объект намного проще.Поскольку вы даже можете определить функции в этом объекте, я не вижу недостатка вообще. – waldgeist

+0

let appState = { func: function() { // blah blah blah } }; – pyrsmk

5

Для создания создать шаблон 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(); 

Update: Согласно @Bergi объяснения, ниже один не является действительным аргументом.

Это работает из-за (см Steven)

> Если я правильно понял CommonJS + реализаций браузера правильно, > выход модуля кэшируются, поэтому экспорт по умолчанию новый MyClass() будет > приведет к чему-то, что ведет себя как singleton (только один экземпляр этого класса будет когда-либо существовать на процесс/клиент в зависимости от > 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

+0

Не делайте этого! Просто не следует использовать синтаксис 'class', если вы не хотите класс! Даже если этот шаблон используется в Flux, это не обязательно хороший шаблон. Кстати, эта цитата совершенно неверна, тривиально создать второй экземпляр, используя 'new singleton.constructor'. – Bergi

+0

@Bergi позволяет предположить, что диспетчер - это реализация класса, и я хочу расширить его функциональность. Таким образом, я создаю еще один класс под названием AppDispacher с помощью JS ES6 'extends' и нужен один экземпляр этого класса. Тогда мне нужно использовать [этот подход] (http://stackoverflow.com/a/26227662/4640228)? Но ** Джейсон ** сказал: «Не имеет смысла». Итак, каков ваш подход? Я ничего не понял. Вы ошиблись. Но он работает и используется в такой компании, как Facebook. :) –

+0

Хорошо, что может иметь смысл, если вы используете несколько диспетчеров в своем приложении, но я бы не назвал его «singleton», а затем даже если у вас есть модули, которые экспортируют только один экземпляр. – Bergi

9

Я должен был сделать то же самое, поэтому здесь простой и прямой способ сделать singleton,реверанс 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)

+2

Не работает с расширяющимся классом. – shinzou

+0

@shinzou Что заставляет вас думать, что это не работает с расширяющимся классом? Все подклассы возвратят один и тот же экземпляр singleton, вот как работают одиночные игры. – Bergi