I am following a tutorial and it says
ES modules uses live bindings. It means a feature to support cyclical dependencies.
But I don't clearly understand this concept. What does this mean?
I am following a tutorial and it says
ES modules uses live bindings. It means a feature to support cyclical dependencies.
But I don't clearly understand this concept. What does this mean?
Live bindings is a concept introduced in ES modules. It means that when the exporting module changes a value, the change will be visible from the importer side. This is not the case for CommonJS modules. Module exports are copied in CommonJS. Hence importing modules cannot see changes happened on the exporter side.
export let count = 1;
export function increment() {
++count;
}
import { count, increment } from './counter.mjs';
console.log(count);
increment();
console.log(count);
$ node --experimental-modules index.mjs
1
2
let count = 1;
function increment() {
++count;
}
exports.count = count;
exports.increment = increment;
const { count, increment } = require('./counter.js');
console.log(count);
increment();
console.log(count);
$ node index.js
1
1
More resources on the topic:
increment
function in the CJS example should mutate exports.count instead. And then the change is reflected everywhere. –
Piecrust Module exports are copied in CommonJS
is wrong. The object called "exports" is exported to every file that use require(), and any change made on that object is reflected in every file that used require() –
Piecrust function increment() { export.count += 1 }
–
Piecrust in CJS, require("./foo")
gets you a reference to the exports
object of foo.js
.
exports.x
to 0 in foo.js
exports.x = 0
bar.js
we get a reference to foo's exports and mutate it:const fooExports = require("./foo")
fooExports.x += 1
Now we put everything in action in main.js
const fooExports = require("./foo") // getting a reference to exports
console.log(fooExports.x) // x is indeed 0
require("./bar") // we execute bar.js that mutate exports
console.log(fooExports.x) // x is now 1, because fooExports is a reference to exports
TLDR: What we receive from require
is not a copy. It's a reference to the exports
object.
Maybe additionally noteworthy would be support for "live bindings" in plain old javascript if one actually wanted that.
var o = { x: 5 }
function increment () { o.x++ }
with (o) {
console.log(x) // 5
increment()
console.log(x) // 6
}
So you could write modules and wrappers to get the wanted behavior without using ESM.
© 2022 - 2024 — McMap. All rights reserved.