sfletche sfletche - 3 months ago 7
Javascript Question

What is the difference between a reference and a binding in Javascript?

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

"The properties and methods you expose on a module's public API are not just normal assignments of values or references. They are actual bindings (almost like pointers) to the identifiers in your inner module definition."

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

let foo = {a: 1};
let bar = foo;


foo
and
bar
now refer to (they are both references to) the same object

bar.b = 2;
console.log(foo.b); // 2


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

// foo.js
let a = 1;
export { a as default };

// bar.js
import a from foo;
console.log(a); // 1


some time later
a
changes in
foo.js


// foo.js
...
a = 2;


and that change is now bound to the imported
a
in
bar.js


// bar.js
...
console.log(a); // 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 must be missing something here...

Answer

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.