ES6 module live bindings: surprise!

ES6 modules are pretty common in new JavaScript projects. They include one feature that can be pretty surprising to folks used to CommonJS modules: live bindings.

Consider the following CommonJS app you want to port to ES6:

// my-library.js
let name = 'default';

function setName(n) {
  name = n;
}

module.exports = { name, setName };

// my-app.js
var { name, setName } = require('./my-library');

console.log( name );
setName( 'ben' );
console.log( name );

That would print:

default
default

A quick port to ES6 might look like this:

// my-library.js
let name = 'default';

function setName(n) {
  name = n;
}

export { name, setName };

// my-app.js
import { name, setName } from './my-library';

console.log( name );
setName( 'ben' );
console.log( name );

But this will print:

default
ben

name changed without anything in my-app.js touching it directly.

This can be useful behavior, but it can also be pretty surprising.