更深入地了解 Javascript 中的模块机制

Deeper understanding of modules mechanisms in Javascript

我正在更深入地了解 ES6 模块,我注意到以下内容我觉得很有趣,我想将其清除。

观察JavaScript 中的所有模块默认都是单例的,所以

// module a.js
let notification = 10;
export default notification;

假设我们有一个模块 b.js 和 c.js,我们在那里导入 a.js 通知将被共享。通知将是只读的。

观察 b.如果从 returns 一个对象的模块中导出一个函数,则会创建一个新对象。

// module a.js
let notification = 10;
export default () => ({
 notification
})

//somewhere in module b.js
import Fn from 'a.js'
let n = Fn().notification; // a new number is created since numbers are immutable in javascript but is this the reason why notification from a.js stays the same?
n = n + 10; // outputs 20

//somewhere in module c.js
import Fn from 'a.js'
let n = Fn().notification; // outputs 10

根据我的理解,这是因为每次都会创建一个新的对象吗?

观察c。如果我们想在模块中共享值,我们需要遵循以下模式吗?

   //module a.js
    let notification = 10;
    export default () => ({
     notification,
     setNotification() {
       notification += 10;
     }
    })

如果在它导入的模块之一中调用了 setNotification,那么在导入模块 a 的任何其他地方,通知的值将自动为 20。

有人能解释一下为什么会发生上述情况吗?我的观察是否正确?

Based on my understanding, this happens because a new object is created every time?

这不是它发生的原因,但是,是的,每次都会创建一个新对象。但是数字不会改变,因为你没有改变它。您刚刚更改了本地 n 变量,该变量与 Fn 编辑的对象 return 的 notification 属性 完全无关。

If we want to share the value in a module we need to follow the following pattern?

这会起作用,但您不必那样做。这同样有效:

export default {
    notification: 10
};

在另一个模块中:

import obj from "./a.js";
console.log(obj.notification); // 10
obj.notification = 20;
console.log(obj.notification); // 20

如果 上面的代码之后你有第三个模块导入并使用它,他们会看到20:

import obj from "./a.js";
console.log(obj.notification); // 20

从它的机制上退一步,虽然,一般来说,以这种方式修改您收到的对象可能不是最佳实践,事实上,您甚至可以考虑冻结您 return 来自模块(或根本 returning 函数以外的对象)所以你可以防止使用模块导出的模块之间出现奇怪的串扰。

这是另一个您可能会觉得有启发性的示例:虽然您导入的绑定是只读的,但它是 实时绑定 到导出模块的本地绑定,本地模块可以更改.所以这有效:

source.js:

export let notification = 10;
export function setNotification(n) {
    notification = n;
};

a.js:

import { notification, setNotification } from "./source.js";
console.log(notification); // 10
setNotification(20);

b.js:

import { notification, setNotification } from "./source.js";
console.log(notification); // 20

main.js:

import "./a.js";
import "./b.js";

您可以将导入的绑定视为导出模块中绑定的非常有效 getter(访问器)。

请注意 a.jsb.js 运行 的顺序,以及它们看到的值,由 main.js 从它们导入的顺序决定(事实上​​他们没有任何循环引用或动态导入)。