Megajin Megajin - 1 year ago 43
Javascript Question

Is it possible to inject global scope into instantiated class in ES6 aka singleton?

First of all I need to apologize because this is going to have alot of code in it, which will bloat this question. However I think this will help to understand my problem a little better.

Let's say I have this given

MainModule
:

'use strict';

/**
* Loads Module from given name.
* @class {LoadModules}
*/
class LoadModules {

constructor(moduleName) {
// define Modulename.
this.moduleName = moduleName;
}

/**
* Initialize module.
* @method init
* @return {void} [nothing]
*/
init() {

// Path Module.
const path = require('path');

// Require Module from given Name.
let ModuleToLoad = require(path.join(__dirname, 'Modules', this.moduleName, this.moduleName + '.js'));
// Instatiate Module.
ModuleToLoad = new ModuleToLoad();
// Start module.
ModuleToLoad.init();
}

}


And an other module which can be loaded into the
MainModule
:

/**
* This is a Module which can be loaded by the MainModule.
* @class {ModuleToBeLoaded}
*/
module.exports = class ModuleToBeLoaded {

constructor() {
/**
* Empty
*/
}

/**
* Initialize newly loaded Module.
* @method init
* @return {void} [nothing]
*/
init() {
console.log('module Loaded');
}

};


As you can see this is used to load modules dynamically, which works perfectly fine.

My problem is that my
MainModule
which loads other modules dynamically can't share its own global scope between the modules, or at least I didn't figure out how. I am well aware that this is complicated since my
MainModule
and
ModuleToBeLoaded
are in different files.

For example I have a
LoggerClass
in my global scope of my
MainModule
:

// This is in the global scope.
const LoggerClass = new Logger();
/**
* LoadModule class stuff comes after this.
*/


I want all Modules to access the LoggerClass as if it were in their own global scope without defining it again and again in each and every module. As an example I would change
console.log
in the
ModuleToBeLoaded
class into this:

/**
* Initialize newly loaded Module.
* @method init
* @return {void} [nothing]
*/
init() {
LoggerClass.log('module Loaded');
}


So basically I define Globals in the
MainModule
and I want to access these Globals in the Code of the
ModuleToBeLoaded
. A possible solution could be to change the
constructor
in the
ModuleToBeLaoded
. Like this:

constructor(LoggerClass) {
// Here I can set LoggerClass internally.
this.LoggerClass = LoggerClass;
}

/**
* Initialize newly loaded Module.
* @method init
* @return {void} [nothing]
*/
init() {
this.LoggerClass.log('module Loaded');
}


Which could allow me to instantiate the class like this:

// Instatiate Module.
ModuleToLoad = new ModuleToLoad(LoggerClass);


Is this the right way, or is there any other solution more preferably?

What I want to achieve is the known pattern
singelton pattern
in ES6.
For more information take a look at this Wikipage: https://en.wikipedia.org/wiki/Singleton_pattern




Sidenote: I'm in a
NodeJS 7.10.0
environment without any 3rd party libraries.

Regards,
Megajin

Answer Source

LoggerClass.js this is how you make singletons (always same instance)

let instance;
module.exports = function () {
  if (!instance) {
    instance = new LoggerClass();
  }
  return instance;
}

class LoggerClass {
  constructor() {
    this.instanceData = Date.now();
  }
  log() {
    console.log(`logging secret instance: ${this.instanceData}`);
  }
}

LoadModules.js

const getLoggerClass = require('./LoggerClass');

module.exports = class LoadModules {
  constructor(moduleName) {
    this.moduleName = moduleName;
  }

  init() {
    const path = require('path');
    // changed the require statement, to make it simpler
    let ModuleToLoad = require(path.join(__dirname, this.moduleName + '.js'));
    ModuleToLoad = new ModuleToLoad(getLoggerClass());
    ModuleToLoad.init();
  }
}

ModuleToLoad.js

module.exports = class ModuleToBeLoaded {
  constructor(logger) {
    this.logger = logger;
  }
  init() {
    console.log('ModuleToBeLoaded module Loaded');
    this.logger.log();
  }
};

ModuleToLoad2.js

module.exports = class ModuleToBeLoaded {
  constructor(logger) {
    this.logger = logger;
  }
  init() {
    console.log('ModuleToBeLoaded2 module Loaded');
    this.logger.log();
  }
};

Demo

> node
> const LoadModules = require('./LoadModules');
> var load = new LoadModules('ModuleToLoad');
> var load2 = new LoadModules('ModuleToLoad2');

> load.init();
ModuleToBeLoaded module Loaded
logging secret instance: 1495528699144
> load2.init();
ModuleToBeLoaded2 module Loaded
logging secret instance: 1495528699144

As you can notice, the instance is the same, according to this.instanceData of LoggerClass

Removed comments to make code more minimal

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download