JavaScript模块的介绍

86 阅读5分钟

JavaScript模块的介绍

说到JavaScript模块,似乎有一些困惑,它们到底是如何工作的,为什么会有不同的形式,我们可以使用它们。今天我将解释一下导出和导入模块的不同方式。

关于JavaScript模块的一些背景

JavaScript程序开始时是简单的脚本或应用程序,代码库相当小,但随着它的不断发展,所以它的用途不断增加,代码库的规模也急剧增加。为了支持这种增长,语言需要支持一种机制,在这种机制下,可以将代码分离或分割成更小的、可重用的单元。Node.JS有一段时间拥有这种能力,然后它被纳入JavaScript的一个功能,称为模块。因此,它们最终成为了语言本身和浏览器的一部分。

根据定义,模块只是一个文件,可以通过exportimport 等指令从其他模块(或文件)导入。

  • 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模块是一个强大的功能,它允许我们更好地组织我们的代码,而且它还允许我们在不同的项目中共享模块。我希望你今天喜欢并学到一些新东西。