46

I've been working with little snippets of JavaScript during 3 years, but now I'm building a React application and I'm getting into it. There is a basic thing that I don't understand. React uses a Dispatcher and Stores to build its Flux pattern, the thing that I don't get is that this Dispatcher is visible in all the application, because Actions use the dispatcher to dispatch actions and Stores register to the Dispatcher to get notified (so it's not a new Dispatcher every time). So, how can I achieve this "global" scope or whatever it is called? How can achieve this using ES6 classes (modules)?

This question may be unclear due to my lack of experience programming real JavaScript, I hope that with the hep of community comments I'll be able to arrange that.

Igor Milla
  • 2,767
  • 4
  • 36
  • 44
vicaba
  • 2,836
  • 1
  • 27
  • 45

2 Answers2

88

You can always assign variables to window.MyClass = whatever (global.MyClass for nodejs) no matter where you are, and access these values from any other file in your application. That's not always the best way to go about sharing data globally in your application though. The module loader in nodejs (or AMD in ES6) takes whatever you export and caches it. Lets say you have a file like:

MyModule.js:

class MyClass {
  constructor() {
    this.someData = 55;
  }
}

export default (new MyClass);

now whenever we require this file from elsewhere, we're ALWAYS being given the SAME instance of MyClass. This means:

file1.js:

import MyClass from './MyModule'
MyClass.someData = 100;

file2.js:

import MyClass from './MyModule'
console.log(MyClass.someData);

This is called the singleton pattern, where we pass around one common instance of your class all throughout your application. So in this manner we're able to access the same instance of MyClass from different files, all without polluting the global scope (we avoid making assignments to global.MyClass but accomplish the same functionality).

Kerem Baydoğan
  • 10,475
  • 1
  • 43
  • 50
David Zorychta
  • 13,039
  • 6
  • 45
  • 81
  • Perfect, I was exporting my classes as ```export default MyClassName``` – vicaba Nov 23 '15 at 16:31
  • 1
    @vicaba for even more context, the pattern I've expressed above is called the singleton pattern ^ where you pass around one common instance of your class in your project – David Zorychta Nov 23 '15 at 16:32
  • I know, but I was not sure if in JavaScript was called the same, Thanks again :) – vicaba Nov 23 '15 at 16:35
  • 1
    Accessing window object parameters is very slow. Don't do it... oh I immediately started writing after just reading the first line. The solution with instance returning is good and works for me. – Pawel Sep 23 '16 at 21:09
  • 2
    The solution with relying on module caching for singleton implementation is not always good. If you're using HMR it won't work. – kubal5003 May 03 '17 at 16:44
  • @kubal5003 That's a good point kubal, that's just what I was thinking, I was hoping you might elaborate more on these implications. It would be good for anyone who reads this. Perhaps you could contribute a better example to the answer. – ADJenks Jul 06 '17 at 02:26
  • 3
    since you are not returning the class but an instance of it. I think you should use `import MyClass` with a lowercase initial character like `import myClass` – Kerem Baydoğan Feb 07 '18 at 23:06
  • + @kubal5003 This might work for **HMR with Webpack** : https://stackoverflow.com/a/40416826/4742733 – Aakash Jun 10 '19 at 02:17
  • @DavidZorychta Thank you David. I am having problems if a class has static methods (using Webpack) - I assume this is an expected behavior because of export `new class` or am I missing something? – Raja Khoury May 13 '20 at 18:13
  • Nevermind I forgot to add the constructor e.g `myClass.constructor.staticMethod()` - will leave the comment may be useful for others. Thank you! – Raja Khoury May 13 '20 at 18:20
8

What you are looking for is to create a singleton. From http://amanvirk.me/singleton-classes-in-es6/.

let instance = null;
export default class Cache{
  constructor() {
    if (!instance) { instance = this; }
    this.time = new Date()

    return instance;
  }
}

I tested this and it works. You would simply replace the this.time = new Date() with this.singletonFunction = function(){}. Where you want to use it do your import then

let aSingleton = (new importName()).singletonFunction;
J. Mark Stevens
  • 4,911
  • 2
  • 13
  • 18