bombali_reyiz
bombali_reyiz

Reputation: 25

NodeJS how to set and get data with only using same module

I have a module to set config. It's working. I want to get config using same module. I don't want to use additional file.

I tried a code something like that:

let config_defaults = { test_option: false };

let active_config;
if(active_config === undefined){ active_config = config_defaults };
exports.getcfg = active_config;

const setcfg function(options){
  options = Object.assign({}, config_defaults, options);
  active_config = options;
  return(options);
}; exports.setcfg = select_config;

setcfg returns changes with no problem. But I can't get changes at getcfg. Is it possible to get changes without using additional file?

Outputs:

console.log( testmodule.setcfg({test_option: true}) ); /* >> Output: { test_option: true } */

console.log( testmodule.getcfg ); /* >> Output: { test_option: false } */

Upvotes: 1

Views: 100

Answers (2)

ghybs
ghybs

Reputation: 53370

You can totally replicate the Java getter/setter behaviour with JavaScript class:

const config_defaults = {
  test_option: false
};

/*export*/ class ConfigManager {
  activeConfig = config_defaults;

  getActiveConfig() {
    return this.activeConfig;
  }

  setActiveConfig(options) {
    options = Object.assign({}, config_defaults, options);
    this.activeConfig = options;
    return options;
  }
}

// import { ConfigManager } from "./testmodule";

const configManager = new ConfigManager();

console.log(configManager.setActiveConfig({
  test_option: true
})); // >> Output: { test_option: true }

console.log(configManager.getActiveConfig()); // >> Output: { test_option: true }


With JavaScript, you do not necessarily need to use a class, especially for a singleton; in this case, an object is enough:

const config_defaults = {
  test_option: false
};

/*export*/ const configManager = {
  activeConfig: config_defaults,

  getActiveConfig() {
    return this.activeConfig;
  },

  setActiveConfig(options) {
    options = Object.assign({}, config_defaults, options);
    this.activeConfig = options;
    return options;
  }
};

// import { configManager } from "./testmodule";

console.log(configManager.setActiveConfig({
  test_option: true
})); // >> Output: { test_option: true }

console.log(configManager.getActiveConfig()); // >> Output: { test_option: true }


Still with JavaScript, you can even hide the getter/setter pattern:

const config_defaults = {
  test_option: false
};

/*export*/ const configManager = {
  _privateActiveConfig: config_defaults,

  get activeConfig() {
    return this._privateActiveConfig;
  },

  set activeConfig(options) {
    options = Object.assign({}, config_defaults, options);
    this._privateActiveConfig = options;
    return options;
  }
};

// import { configManager } from "./testModule";

console.log(configManager.activeConfig = {
  test_option: true
}); // >> Output: { test_option: true }

console.log(configManager.activeConfig); // >> Output: { test_option: true }

Upvotes: 1

ghybs
ghybs

Reputation: 53370

The cause of the issue is that you already assign the reference to an active_config object when defining exports.getcfg, but later in setcfg, active_config is re-assigned a reference to a different object.

You could compare the assignment to an object reference as writing down the address of that object in a variable. If you re-assign active_config, all other variables that knew its previous address still reference that old content.

See e.g. Is JavaScript a pass-by-reference or pass-by-value language?

You have 2 easy solutions:

  1. Perform a deep mutation: instead of re-assigning the content of active_config directly, you change the value of one of its members, as if it was a "routing switch"

  2. Make the getter a function, which can then use the most recent version of the scope variable when executed

const exports = testmodule = {};

const config_defaults = {
  test_option: false
};

// Option 1: expose a switch instead of directly the changing variable
const active_config_switch = {
  active_config: config_defaults,
};
exports.getcfg_switch = active_config_switch;

// Option 2: getter as a function
let active_config = config_defaults;
exports.getcfgFn = function() {
  return active_config;
}

const select_config = function(options) {
  options = Object.assign({}, config_defaults, options);
  active_config_switch.active_config = options; // Option 1: deep mutation
  active_config = options;
  return options;
};
exports.setcfg = select_config;

console.log(testmodule.setcfg({
  test_option: true
})); /* >> Output: { test_option: true } */

// Option 1: read the deep member
console.log(testmodule.getcfg_switch.active_config); /* >> Output: { test_option: true } */

// Option 2: execute the getter function
console.log(testmodule.getcfgFn()); /* >> Output: { test_option: true } */

Upvotes: 0

Related Questions