【问题标题】:Exporting mutable values: import vs require导出可变值:import vs require
【发布时间】:2021-11-12 18:10:57
【问题描述】:

在导出/导入可变值时,我试图了解 importrequire 之间的区别。

想象一个文件a.ts

export let a = 1;
export function f() {
  a = 2;
}

然后是一个主文件的三个版本,index1.ts

import { a, f } from "./a";

console.log(a); // 1
f();
console.log(a); // 2

index2.ts

const { a, f } = require("./a");

console.log(a); // 1
f();
console.log(a); // 1

index3.ts

const _ = require("./a");

console.log(_.a); // 1
_.f();
console.log(_.a); // 2
  • 我希望 index1.ts 产生与 index2.ts 相同的输出,但事实并非如此。 imported a 总是从 a.ts 引用实际的 a 变量。有什么保证会一直如此?规范是否强制执行此行为?
  • index3.ts 有效,因为require 返回的对象的属性是getters。同样,这是否保证始终正确?例如,我们可以依赖它来设计一个库吗?

【问题讨论】:

  • import 创建一个别名,而不是一个新变量。 const 确实创建了一个变量来获取值的副本。

标签: typescript ecmascript-6


【解决方案1】:

使用import 导入的标识符可能会表现得很奇怪 - 如果导出它们的模块重新分配导出的内容,它们似乎可以自行重新分配自己,这就是原因

import { a, f } from './a';
console.log(a);
f()
console.log(a);

确实可以记录 1,然后是 2 - 这是您在任何其他类型的 JavaScript 中都看不到的。

规范是否强制这种行为?

是的,确实如此。

另一方面,使用require 而不是import,会返回另一个模块导出的命名空间对象,而不是创建行为异常的模块变量。该对象的工作方式就像您期望 Javascript 中的任何其他对象一样 - 如果您将对象的值解构为变量,则这些值不会“自行更改”,除非您在当前范围内明确执行 a = someOtherValue 之类的操作。

index3.ts 之所以有效,是因为 require 返回的对象的属性是 getter。同样,这是否保证始终正确?例如,我们可以依赖它来设计一个库吗?

这有点像命名空间对象属性值在被导出的模块重新分配它们时被重新分配。如果你有

// foo.ts
export let a = 1;
export function f() {
  a = 2;
}

那么在别处导入的命名空间对象将是一个包含

live结构
{
  a: currentValueOfAInFoo,
  f: currentValueOfFInFoo,
}

也就是说,虽然 可能 依赖于这种行为,但我强烈建议不要编写依赖它的代码,因为与人们通常期望标识符的行为方式相比,它非常奇怪- 这可能会让代码阅读者和代码编写者感到困惑。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-12-19
    • 1970-01-01
    • 2017-05-01
    • 2021-03-16
    • 1970-01-01
    • 2019-04-16
    • 1970-01-01
    • 2016-11-05
    相关资源
    最近更新 更多