ES6 命名导出和默认导出之间的可变差异

Posted

技术标签:

【中文标题】ES6 命名导出和默认导出之间的可变差异【英文标题】:Mutable difference between ES6 named and default exports 【发布时间】:2020-02-14 15:56:00 【问题描述】:

当从 ES6 模块导入/导出数据时,该数据的可变性在命名导入和导出之间似乎有所不同。这是有原因的还是我不理解的一些根本差异?

// 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

在这两种情况下,我都希望count 增加。但是,这只发生在使用命名导出时。

【问题讨论】:

不管怎样,上面的代码在用 Babel 7.6.0 转译后进行了测试。 不转译也会发生同样的事情吗? @JohnnyCrain 如果您仔细观察转译的代码,该函数会更改名称 export 而不是默认的导出计数 @dandavis 无论是转译还是直接由 Chromium 运行,结果都是一样的。 【参考方案1】:

问题在于您使用了export default count;,它不会导出count 绑定(允许通过导入为可变变量别名)但实际上创建了一个新的隐藏变量,该变量获取分配的初始值但从未更改之后。

export default count;

去糖

let *default* = count; // where *default* is a guaranteed collision-free identifier
export  *default* as default 

你想要的是

// 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

另见How can I alias a default import in javascript?。

【讨论】:

【参考方案2】:

这是因为计数是数字而不是对象。通过导入默认值,您将计数值分配给新变量。通过命名导入,您可以只读复制对象。 考虑一下:

// counter.js
export let count = a:0;
export const incrementCount = () => count.a += 1;
export default (function() return count.a)();

当你运行时:

// main-default.js
import countdefault,  count, incrementCount  from './counter.mjs';
console.log(countdefault, count);
incrementCount();
incrementCount();
console.log(countdefault, count);

你得到:

0 a: 0

0 a: 2

但是当您将计数器导出更改为对象时:

// counter.js
export let count = a:0;
export const incrementCount = () => count.a += 1;
export default (function() return count)();

你得到:

a: 0 a: 0

a: 2 a: 2

【讨论】:

这是错误的。导入仍然可以是别名,它与值是否为对象无关。

以上是关于ES6 命名导出和默认导出之间的可变差异的主要内容,如果未能解决你的问题,请参考以下文章

JS ES6:声明const并将其导出为默认值与将其直接声明为默认导出之间的区别

笑话:当同一个模块也有命名导出时,如何模拟默认导出组件?

使用 ES5 语法在 Node 中混合默认和命名导出

如何从命名空间导出,访问默认值? [复制]

简明 ES6 模块

ES6 如何做多个默认导出