How can I get constant variable with the global object in Nodejs?

Viewed 964

I wanted to get a constant variable with the global object to use it dynamically but global.myconstant doesn't work but global.myvar works.

λ node
> const myconstant = true
undefined
> global.myconstant
undefined
> var myvar = true
undefined
> global.myvar
true
> global.const
undefined

That I want to do :

const myconstant = () => { console.log("ok const"); };
var myvariable = () => { console.log("ok var"); };

const watchlist = {
  myconstant: "file1.html",
  myvariable: "file2.html"
};

Object.keys(watchlist).forEach((taskName) => {
  try {
    global[taskName](); //doesn't work with const
  } catch (e) {
    console.error("error", taskName);
  }
});

Actual output :

error myconstant
ok var

Wanted output :

ok const
ok var

Live demo : https://repl.it/repls/SunnyScholarlyPasswords

How can I get const variable with string ? Without replace const by var.

2 Answers

Only variables declared with var get implicitly assigned to the global object. If you want to create a non-reassignable property, you should use Object.defineProperty instead. For example, in the browser, referring to window instead of global:

Object.defineProperty(
  window,
  'myconstant',
  {
    value: () => { console.log("ok const"); },
    configurable: false
  }
);
var myvariable = () => { console.log("ok var"); };

const watchlist = {
  myconstant: "file1.html",
  myvariable: "file2.html"
};

Object.keys(watchlist).forEach((taskName) => {
  try {
    window[taskName]();
  } catch (e) {
    console.error("error", taskName);
  }
});

// Won't reassign, and will throw an error in strict mode:
window.myconstant = 'foo';
console.log(typeof window.myconstant);

The configurable: false is the key, though it's optional - it defaults to false anyway. Non-configurable properties can't be modified or deleted.

Described behaviour is natural to but not Node REPL but not the code that is evaluated in modules. Variables in module scope don't leak to global because they are defined in module scope, this applies to both var and const. This is what will happen in Node module:

const myconstant = 1;
var myvariable = 2;

console.log(global.myconstant) // undefined
console.log(global.myvariable) // undefined

The reason why this happens in REPL is that the code is evaluated in global scope. Described behaviour could be replicated in module scope with indirect eval:

(0, eval)(`
  const myconstant = 1;
  var myvariable = 2;
`);

console.log(global.myconstant) // undefined
console.log(global.myvariable) // 2

This is the difference between var and block-scoped variables (const, etc.). When defined in global scope, var results in defining a property on global variable (global in Node), while const doesn't.

If the intention is to define a global, it should be defined as a property:

global.myconstant = 1;
global.myvariable = 2;

In case it's needed to define global variable that won't be reassigned, a descriptor should be used (as another answer already explains):

Object.defineProperty(global, 'myconstant', {
  value: 1,
  configurable: false,
  writable: false
});

The use of globals for local purposes is generally discouraged, especially in modular environments like Node.

Related