Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are JavaScript default exports not live?

Tags:

javascript

Why is the default export not live like a named export is?

//------ lib.js ------
export let counter = 0;
export function incCounter() {
  counter++;
}
export default counter;


//------ main1.js ------
import { counter, incCounter } from "./lib";
import $counter from "./lib";

console.log({ $counter, counter }); // {$counter: 0, counter: 0}
incCounter();
console.log({ $counter, counter }); // {$counter: 0, counter: 1}

That shows that the named counter export is live but the default export isn't. Why?

like image 543
Thomas Avatar asked Oct 18 '25 15:10

Thomas


2 Answers

As far as I've ever been able to determine, it's purely because that's the decision that was made by the people defining modules, because they wanted to allow exporting the result of arbitrary expressions. What follows export default is an expression, not a binding (unless it's a function declaration or class declaration). For instance, this is a valid default export:

export default 6 * 7;

So your export default counter; is evaluating the value of counter and then exporting that, not a live binding.

You can see this in the grammars at the top of the modules section of the specification:

export default HoistableDeclaration[~Yield, +Await, +Default]

export default ClassDeclaration[~Yield, +Await, +Default]

export default [lookahead ∉ { function, async [no LineTerminator here] function, class }] AssignmentExpression[+In, ~Yield, +Await] ;

The first two cover function declarations and class declarations; the third, which exports the result of an AssignmentExpression, is what your code is using.

It could have been defined differently, it just wasn't. (Subjectively: Probably for a good reason, a lot of thought went into the design of modules.)

I suspect the reason for wanting to be able to export the results of arbitrary expressions was primarily around using default export to export the result of an object literal:

export default {
    something: "some value",
    // ...
};

That's useful when using a module as a configuration file, for instance.

like image 93
T.J. Crowder Avatar answered Oct 20 '25 05:10

T.J. Crowder


Sometimes they are! It depends on the syntax you use.

This is not a live binding:

export let counter = 0;
export function incCounter() {
  counter++;
}
export default counter;

But this is!

export let counter = 0;
export function incCounter() {
  counter++;
}
export { counter as default };
like image 28
Ben McCann Avatar answered Oct 20 '25 04:10

Ben McCann