当命名的 ES6 导出被异步改变时,为什么导入器会接收到变化?
When named ES6 exports are asynchronously mutated, why is the change picked up by importers?
考虑以下示例:
// module.mjs
export let member = "initial"
setTimeout(() => {
member = "mutated"
}, 2000)
// index.mjs
import { member } from "./module.mjs"
setInterval(() => {
console.log(member)
}, 300);
如果你 运行 index.mjs
它会打印 "initial"
几次并在 2 秒超时后开始打印 "mutated"
.
这让我很惊讶。我预计它会继续打印 "initial"
,因为对 member
的引用已更改。如果我的 index.mjs
看起来像这样
,我不会感到惊讶
// index.mjs
import * as allExports from "./module.mjs"
setInterval(() => {
console.log(allExports.member)
}, 300);
对 allExports
的引用没有改变。因此,通过以 属性 的形式访问 member
,我可以访问新的引用。公平地说,这会产生相同的结果。
但为什么它在第一种情况下也有效?每次构造函数调用的上下文时,导入引用都会更新吗?好吧,那么它也应该与默认导出一起使用。但是,在这样调整代码之后:
// module.mjs
let member = "initial"
export default member
setTimeout(() => {
member = "mutated"
}, 2000)
// index.mjs
import member from "./module.mjs"
setInterval(() => {
console.log(member)
}, 300);
根据我的直觉,index.mjs
一直在打印 "initial"
。嗯,也许默认导出和命名导出之间存在根本区别。如果我这样做会怎样:
// module.mjs
export let member = "initial"
setTimeout(() => {
member = "mutated"
}, 2000)
// index.mjs
import * as allExports from "./module.mjs"
let { member } = allExports
setInterval(() => {
console.log(member)
}, 300);
哇,它一直在打印 "initial"
。这是我真正感到困惑的地方。我一直认为
import { member } from "./module.mjs"
只是将所有named-exports
导入为对象然后进行解构的缩写。
所以我的问题是:named-exports
这种独特行为的基本原理是什么?
这是因为从技术上讲,ES6 模块导出和导入绑定而不是值。当你这样做时:
export let test = 0
您需要考虑导出的是 test
而不是 0
。这意味着对变量的任何更改都将反映在它们的导入中。
一直打印的原因 initial
:
// index.mjs
import * as allExports from "./module.mjs"
let { member } = allExports
setInterval(() => {
console.log(member)
}, 300);
是因为allExports
is a special object。您正在此处创建一个新绑定并且值被复制,但您正在丢失导入的绑定。
考虑以下示例:
// module.mjs
export let member = "initial"
setTimeout(() => {
member = "mutated"
}, 2000)
// index.mjs
import { member } from "./module.mjs"
setInterval(() => {
console.log(member)
}, 300);
如果你 运行 index.mjs
它会打印 "initial"
几次并在 2 秒超时后开始打印 "mutated"
.
这让我很惊讶。我预计它会继续打印 "initial"
,因为对 member
的引用已更改。如果我的 index.mjs
看起来像这样
// index.mjs
import * as allExports from "./module.mjs"
setInterval(() => {
console.log(allExports.member)
}, 300);
对 allExports
的引用没有改变。因此,通过以 属性 的形式访问 member
,我可以访问新的引用。公平地说,这会产生相同的结果。
但为什么它在第一种情况下也有效?每次构造函数调用的上下文时,导入引用都会更新吗?好吧,那么它也应该与默认导出一起使用。但是,在这样调整代码之后:
// module.mjs
let member = "initial"
export default member
setTimeout(() => {
member = "mutated"
}, 2000)
// index.mjs
import member from "./module.mjs"
setInterval(() => {
console.log(member)
}, 300);
根据我的直觉,index.mjs
一直在打印 "initial"
。嗯,也许默认导出和命名导出之间存在根本区别。如果我这样做会怎样:
// module.mjs
export let member = "initial"
setTimeout(() => {
member = "mutated"
}, 2000)
// index.mjs
import * as allExports from "./module.mjs"
let { member } = allExports
setInterval(() => {
console.log(member)
}, 300);
哇,它一直在打印 "initial"
。这是我真正感到困惑的地方。我一直认为
import { member } from "./module.mjs"
只是将所有named-exports
导入为对象然后进行解构的缩写。
所以我的问题是:named-exports
这种独特行为的基本原理是什么?
这是因为从技术上讲,ES6 模块导出和导入绑定而不是值。当你这样做时:
export let test = 0
您需要考虑导出的是 test
而不是 0
。这意味着对变量的任何更改都将反映在它们的导入中。
一直打印的原因 initial
:
// index.mjs
import * as allExports from "./module.mjs"
let { member } = allExports
setInterval(() => {
console.log(member)
}, 300);
是因为allExports
is a special object。您正在此处创建一个新绑定并且值被复制,但您正在丢失导入的绑定。