2014-10-05 55 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/轉換辛格爾頓JS對象使用ES6類

這有什麼意義轉換2單一對象使用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 }; 
+2

號如果你有一個單身,你不需要在JavaScript中的一類。類用於構造多個實例。 – Bergi 2014-10-05 18:06:32

+0

@bergi,這就是我的想法。但只是檢查是否有什麼我失蹤。 – justingordon 2014-10-05 22:09:59

回答

32

我認爲單身人士(管理他們自己的單身人士生命的班級)在任何語言中都是不必要的。這並不是說singleton的生命週期沒有用處,只是我更喜歡除了班級以外的其他東西來管理對象的生命週期,例如DI容器。

也就是說,singleton模式可以應用於JavaScript類,借用ActionScript中使用的「SingletonEnforcer」模式。在將現有的使用單例的代碼移植到ES6中時,我可以看到想要做類似這樣的事情。

在這種情況下,您的想法是您可以通過一個公共靜態instance getter來創建一個私有(通過一個未公開的Symbol)的靜態singleton實例。然後,將構造函數限制爲可以訪問不在模塊外部暴露的特殊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/是更好的方法,因爲它在構造函數本身內部管理狀態 – 2015-05-20 09:45:46

+0

@AmanVirk如果您要擴展該類,該方法是否可行? – 2015-09-03 17:54:08

+1

IMO在實例獲取器中使用這個有點奇怪。 它不能引用類本身,因爲它是一種靜態方法。 我寧願把 ''' const instance = null; ''' 以外的類,然後在代碼中使用實例。無論如何,處理器將把所有這些都放在關閉中,所以最終它將成爲一個私有變量。 除此之外,它似乎是一個很好的解決方案! – dejakob 2016-02-06 16:12:49

57

號是沒有意義的。

這裏有一個單一對象的ES6一個非常簡單的例子:

let appState = {}; 
export default appState; 

如果你真的想在你的單身的方法來使用一個類,我會建議不要使用「靜態」,因爲它多好睏惑對於一個單身至少JS,而是返回類像這樣一個單獨的實例...

class SomeClassUsedOnlyAsASingleton { 
    // implementation 
} 

export default new SomeClassUsedOnlyAsASingleton(); 

這樣你仍然可以使用所有類的東西,你喜歡JavaScript的報價,但會降低混亂,因爲IMO靜態不完全支持在JavaScript類中,因爲它是類似於c#或Java的語言,因爲它只支持靜態方法,除非你直接僞造它並將它們直接附加到一個類(在撰寫本文時)。

+3

或者只是一行'export default let appState = {};':-) – Bergi 2015-04-30 21:57:03

+0

@Jason:謝謝,你真的睜開了眼睛。我也嘗試過定義一個單例類,但有一個單一的對象要簡單得多。正如你甚至可以在這個對象中定義函數一樣,我完全看不出任何缺點。 – waldgeist 2015-08-21 09:27:49

+0

let appState = { func:function(){ //等等等等 } }; – pyrsmk 2015-09-29 06:44:39

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

更新:根據@Bergi解釋,下面一個是不是一個有效的參數。

這工作,因爲(參考Steven

>如果我理解正確CommonJS的+瀏覽器實現中, >模塊的輸出緩存,所以出口默認新MyClass的()將 >導致某行爲表現爲單例行爲(根據運行的環境,只有一個 >這個類的實例將永遠存在於每個進程/客戶端)。

你可以在這裏找到一個例子ES6 Singleton

:該圖案在助焊劑Dispacher

助焊劑使用: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 2015-11-12 22:56:06

+0

@Bergi讓我們假設Dispatcher是一個類實現,我想擴展它的功能。所以,我使用JS ES6'extends'創建了另一個名爲AppDispacher的類,並且需要該類的單個實例。那我必須使用[這種方法](http://stackoverflow.com/a/26227662/4640228)?但** Jason **說「沒有意義」。那麼,你的方法是什麼?我不明白一件事。你讓這個答案錯了​​。但它在Facebook這樣的公司工作和使用。 :) – 2015-11-13 12:11:57

+0

那麼,如果你在你的應用程序中使用多個調度程序,這可能是有意義的,但即使你有隻導出單個實例的模塊,我也不會稱之爲「單例」。 – Bergi 2015-11-13 12:20:24

9

我必須這樣做,所以這裏是一個簡單而直接的做單身的方法, 屈膝禮來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(辛格爾頓)

+2

不適用於擴展類。 – shinzou 2017-04-25 10:41:12

+0

@shinzou是什麼讓你覺得它不適用於擴展類?所有的子類都會返回相同的單例實例,這就是單例的工作原理。 – Bergi 2017-12-23 19:44:11