问题
When importing/exporting data from ES6 modules, mutability of that data appears to be different between named imports and exports. Is there a reason for this or some fundamental difference I'm not understanding?
// counter.js
export let count = 0;
export const incrementCount = () => count += 1;
export default count;
// main-default.js
import count, { incrementCount } from './counter';
console.log(count); // 0
incrementCount();
incrementCount();
console.log(count); // 0
// main-named.js
import { count, incrementCount } from './counter';
console.log(count); // 0
incrementCount();
incrementCount();
console.log(count); // 2
In both scenarios, I would expect count
to increment. However, this only happens when using named exports.
回答1:
It is because count is number not object. By importing default you are assigning value of count to new variable. By named import you have readonly copy like object. Consider this:
// counter.js
export let count = {a:0};
export const incrementCount = () => count.a += 1;
export default (function(){ return count.a})();
When you run:
// main-default.js
import countdefault, { count, incrementCount } from './counter.mjs';
console.log(countdefault, count);
incrementCount();
incrementCount();
console.log(countdefault, count);
you get:
0 { a: 0 }
0 { a: 2 }
but when you change counter export to object:
// counter.js
export let count = {a:0};
export const incrementCount = () => count.a += 1;
export default (function(){ return count})();
you get:
{ a: 0 } { a: 0 }
{ a: 2 } { a: 2 }
回答2:
The problem is that you used export default count;
, which does not export the count
binding (allowing aliasing the mutable variable by an import) but actually creates a new, hidden variable that gets the initial value assigned but is never changed afterwards.
export default count;
desugars to
let *default* = count; // where *default* is a guaranteed collision-free identifier
export { *default* as default }
What you want instead is
// counter.js
let count = 0;
export const incrementCount = () => count += 1;
export { count as default }
// main-default.js
import countA, { default as countB, incrementCount } from './counter';
console.log(countA, countB); // 0, 0
incrementCount();
console.log(countA, countB); // 1, 1
See also How can I alias a default import in Javascript?.
来源:https://stackoverflow.com/questions/58437520/mutable-difference-between-es6-named-and-default-exports