Search code examples
javascriptreferenceecmascript-6es6-modules

Javascript reference vs binding...what's the difference?


I recently read the following in Kyle Simpson's You Don't Know JS: ES6

"[ES6 modules export] actual bindings (almost like pointers) to the identifiers in your inner module definition."

My confusion is how these bindings differ from references...

I understand that a reference in JS is only applicable to non-primitive types (like objects), so that given

let object1 = {a: 1};
let object2 = object1;

object1 and object2 now refer to (they are both references to) the same object.
If I add a property to object2, I am also adding a property to object1

object2.b = 2;
console.log(object1.b); // 2

And I can see that a binding can apply to both primitive types and non-primitive types

// foo.js
export let count = 1;
export function incrementCount() { count++; }

// bar.js
import {count, incrementCount} from foo;
console.log(count); // 1
incrementCount();
console.log(count); // 2

Is a binding just like a reference, except that primitive values can also share a binding (while references are limited to non-primitive types)?

I feel like I'm missing something here...


Solution

  • A binding is a very generic term for "what a name refers to". Every identifier in a scope is bound to something. Usually they resolve to variables in a variable environment (storage slots in an environment record), but there are exceptions (e.g. with or the global object).

    A reference is a term for a pointer to some kind of structure. For example, objects are known as "reference values" because they reference the container of mutable properties with an identity.

    ES6 modules are now introducing a new type of binding, one that was unknown before. It is not a usual variable, but literally a reference to another variable - the one exported from the other module. If the module variable changes, this will be reflected by the import - they both point to the same environment record slot.
    An export declaration adds a mapping from a local name to a name in the module interface, while an import declaration adds a mapping from a name in the respective module interface to a local name. When a module is instantiated, an indirect binding is created that points to the same environment as the local binding in the exporting module.