The behavior here, which you can see in ES6 modules:
console.log(foo); // undefined
init();
console.log(foo); // 42
should feel pretty odd in comparison to how JS normally works - foo
appears to be a local identifier, but if it happens to be an import from another module, if the other module's export changes, the foo
binding wherever it's imported will change as well.
Without using ES6 modules, there is no (reasonable) way to replicate that sort of behavior using a single identifier.
You can use ES6 modules in Node if you want, though. Use the original code with the ES6 module syntax, and then run:
node --experimental-modules index.mjs
Build systems like Webpack can also transpile code written in ES6 modules into vanilla JS, though such transpiled code ends up turning the imports into a namespace object. Eg, this:
import { foo, init } from "./foo";
init();
console.log(foo); // 42
will turn into something like
const fooNamespace = __webpack_require__("./foo.js");
fooNamespace.init();
console.log(fooNamespace.foo);
It's just like if you had a reference to an object which, when a function inside it is called, mutates the object. You could implement this if you wanted.
const obj = {
foo: undefined,
init() { obj.foo = 42 }
};
module.exports = obj;
Although one can use ES6 modules to make imported identifiers seemingly reassign themselves on their own, keep in mind that, since such code is potentially confusing, some prefer to avoid such patterns entirely.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…