JavaScript模块的介绍
说到JavaScript模块,似乎有一些困惑,它们到底是如何工作的,为什么会有不同的形式,我们可以使用它们。今天我将解释一下导出和导入模块的不同方式。
关于JavaScript模块的一些背景
JavaScript程序开始时是简单的脚本或应用程序,代码库相当小,但随着它的不断发展,所以它的用途不断增加,代码库的规模也急剧增加。为了支持这种增长,语言需要支持一种机制,在这种机制下,可以将代码分离或分割成更小的、可重用的单元。Node.JS有一段时间拥有这种能力,然后它被纳入JavaScript的一个功能,称为模块。因此,它们最终成为了语言本身和浏览器的一部分。
根据定义,模块只是一个文件,可以通过export 和import 等指令从其他模块(或文件)导入。
export:关键字标记变量和函数,这些变量和函数应该可以从当前模块之外访问。import: 允许从其他模块导入功能。
我们稍后会再来讨论这个问题。
介绍一个例子
为了演示模块的使用,我们将创建一个简单的user 模块,它将暴露一个User 类。让我们回顾一下这个项目的基本结构。
index.html
scripts/
index.js
modules/
user.js
我们的应用程序将非常简单,它只是在屏幕上显示一个用户的名字,但有趣的是,这个名字将来自User 类的一个对象实例。让我们通过一个现场演示来看看它的操作。
让我们详细看看那里的各个部分是怎么回事
导出模块用户
为了访问User 类,我们需要做的第一件事是从模块中导出它。为此,我们利用了export 语句。
在创建JavaScript模块时,导出语句用于从模块中导出与函数、对象或原始值的活体绑定,这样它们就可以被其他程序使用,并使用导入语句。
让我们在我们的代码中看到这一点。
// file: scripts/modules/user.js
export class User {
constructor(name) {
this.name = name;
}
}
现在模块已经被导出,我们可以通过导入在其他模块中使用它。
导入模块User
静态导入语句用于导入由另一模块导出的只读活体绑定。无论你是否声明,导入的模块都处于严格模式。import 语句不能在嵌入式脚本中使用,除非这样的脚本有 type="module"。导入的绑定被称为实时绑定,因为它们会被导出绑定的模块所更新。
让我们在我们的例子中看到它
//file: scripts/index.js
import { User } from './modules/user.js'
const user = new User('Juan')
document.getElementById('user-name').innerText = user.name;
import 语句允许我们从一个模块导入特定的绑定。有几种不同的方法来指定我们要导入的东西,我们将在后面的文章中讨论。现在,在我们的例子中,我们只是从指定的模块(或文件)中导入User 。
导入后我们可以使用该对象,因为它是同一文件的一部分。
默认导出与命名导出
到目前为止,我们通过名字导出一个类,但有2种不同的方式从模块中导出
- 命名导出(每个模块有零个或多个导出)。
- 默认导出 (每个模块只有一个)
下面是一些命名导出的例子。
// export features declared earlier
export { myFunction, myVariable };
// export individual features (can export var, let, const, function, class)
export let myVariable = Math.sqrt(2);
export function myFunction() { ... };
默认导出。
// export feature declared earlier as default
export { myFunction as default };
// export individual features as default
export default function () { ... }
export default class { .. }
命名导出对于导出几个值是很有用的。在导入时,必须使用与相应对象相同的名称。但是默认导出可以用任何名字导入,比如说。
// file: myk.js
const k = 12
export default k
// file: main.js
import m from './myk'
console.log(m)
当使用命名导出时,也可以为导出的值指定一个自定义的名称,就像下面的例子。
const name = 'value'
export {
name as newName
}
导出的值现在可以被导入为newName ,而不是name 。
导入
我们已经看到了一些例子,说明我们如何从模块中导入命名或默认导出。但在导入时有更多的选择。
导入一个默认的输出
import something from 'mymodule'
console.log(something)
导入一个命名的出口
import { var1, var2 } from 'mymodule'
console.log(var1)
console.log(var2)
重命名一个导入
import { var1 as myvar, var2 } from 'mymodule'
// Now myvar will be available instead of var1
console.log(myvar)
console.log(var2)
从一个模块中全部导入
import * as anyName from 'mymodule'
console.log(anyName.var1)
console.log(anyName.var2)
console.log(anyName.default)
到目前为止,我们在这里描述的所有方法都是静态导入,这意味着你把它们放在文件的顶部,模块的内容总是被导入。但情况并非如此,你也可以使用动态导入。
动态导入
这允许你只在需要的时候动态加载模块,而不是提前加载所有模块。这有一些明显的性能优势;让我们继续阅读,看看它是如何工作的。
这个新功能允许你将 import() 作为一个函数来调用,将模块的路径作为参数传给它。它返回一个Promise,这个Promise与一个模块对象一起完成,使你能够访问该对象的出口,例如
import('./modules/myModule.js')
.then((module) => {
// Do something with the module.
});
结合默认导出和命名导出
你没看错!有可能结合默认的和命名的,正如你所期望的,你可以同时导入它们。让我们看一个例子。
//file: mymodule.js
export const named = 'named export'
export function test() {
console.log('exported function')
}
export default 'default export';
而我们可以使用以下任何一种情况来导入它们。
//another file:
import anyName from './mymodule' // where anyName is the default export
// or both named exports
import { named, test } from './mymodule';
// or just one
import { named } from './mymodule';
// or all of them together
import anyName, { named, test } from './mymodule';
总结
JavaScript模块是一个强大的功能,它允许我们更好地组织我们的代码,而且它还允许我们在不同的项目中共享模块。我希望你今天喜欢并学到一些新东西。