在JavaScript中导入模块的方法

511 阅读8分钟

如果你有一个非常复杂的应用程序,并且不得不滚动浏览数百或数千行代码,那么调试或只是理解应用程序的工作就变得更加复杂。幸运的是,Javascript通过 "导入"和 "导出"来帮助我们。

Javascript的导入

Javascript的导入语句用于导入由另一个模块导出的绑定。使用import,当代码是小块的时候,更容易管理。

这就是把函数保持在只有一个任务,或让文件一次只包含几个或一个组件背后的想法。

如果你有一个复杂的网络应用,并且不得不滚动浏览数百或数千行代码,那么调试或只是理解一个应用的工作就变得更加困难。

这就是你如何在一个文件中写代码,并将该代码共享给另一个文件。

如果你在前端或后端使用ES6语法,那么导入和导出的想法是一样的,但语法略有不同。

你现在使用'import'语句,而不是文件顶部的'require',你也可以有'exportdefault或export'语句,而不是module.exports。如果你只有一个东西要从文件或多个模块中导出。

除非脚本有type=' module',否则import语句不能在嵌入式脚本中使用。

还有一种类似函数的动态import(),它不需要 type=' module 的脚本。

动态导入在你希望有条件地加载模块或按需加载模块的情况下很有用。然而,静态形式对于初始加载依赖性来说是比较好的。

import 模块的语法 如下。它有这么多语法,因为它取决于我们是否从文件中导入单个或多个内容:

import defaultExport from 'module_name';
import * as name from 'module_name';
import { content } from 'module_name';
import { content as alias } from 'module_name';
import { content , content2 } from 'module_name';
import { content , content2 } from "module-name/path/to/specific/un-exported/file";
import { content , content2 as alias2 , [...] } from 'module_name';
import defaultExport, { content [ , [...] ] } from 'module_name';
import defaultExport, * as name from 'module_name';
import 'module_name';
var content = import('module_name');

name参数是 "模块对象",它将被用作命名空间来指代出口。

export参数指定单独命名的出口,而import \ as name语法则导入所有的出口。下面是澄清语法的例子。

创建一个项目文件夹,在该项目文件夹内,创建三个文件:

  1. app.js
  2. data.js
  3. start.js

现在,node.js默认不支持导入-导出功能。因此,我们需要一个babel转码器 来实现工作。

为此,我们需要安装两个软件包。所以先到终端输入以下命令,生成package.json 文件:

npm init -y

然后我们需要安装两个node模块。所以键入以下命令:

npm install babel-register babel-preset-env --save-dev

它将在node_modules 文件夹中安装这些模块。

现在,在 start.js文件中写下以下代码:

// start.js

require('babel-register')({
    presets: ['env']
});

module.exports = require('./app.js')

我们将运行这个文件来运行app.js 文件中的导入-导出语句。

下一步是在data.js 文件内写下以下代码:

// data.js

export const add = (x, y) => {
    return x + y
}

添加函数接受参数并添加它们,并返回结果。这里的语法是ES6,我们使用了箭头函数

最后,在app.js 文件中添加以下代码:

// app.js

import { add } from './data';

console.log(add(2, 3));

在这里,我们已经导入了数据 模块和该模块中的特定添加 函数。

现在,运行start.js 文件,看看输出情况:

node start.js

Javascript Import Statement Tutorial

在上面的例子中,我们使用了从一个模块导入一个单一的出口。

如果我们有多个导出模块,那么我们可以导入各种模块。

在Javascript中导入多个模块

现在,我们将在data.js 文件中创建另一个模块:

// data.js

export const add = (x, y) => {
    return x + y
}

export const subtract = (x, y) => {
    return x - y;
}

现在,在app.js 文件内导入这两个模块:

// app.js

import { add, subtract } from './data';

console.log(`The addition is: ${add(2, 3)}`);
console.log(`The suntraction is: ${subtract(21, 19)}`);

最后,运行start.js 文件,看看输出情况:

Javascript Import Statement Tutorial With Example

使用更方便的别名的Javascript导入

你可以在导入一个出口时重命名它。例如,这样把sub插入到当前的范围内。

请看app.js 文件。我们把模块的subtracts重命名为sub:

import { add, subtract as sub } from './data';

console.log(`The addition is: ${add(2, 3)}`);
console.log(`The suntraction is: ${sub(21, 19)}`);

在Javascript中导入默认值

假设;我们在data.js 文件中只有一个导出默认模块:

// data.js

const add = (x, y) => {
    return x + y
}
export default add;

在上面的代码中,我们使用了export default 关键字,这意味着我们只从这个文件中导出了add 模块。

现在,如果我们在data.js 文件内有一个默认模块,我们可以像下面这样在app.js 文件内导入它:

// app.js

import add from './data';

console.log(`The addition is: ${add(2, 3)}`);

请看下面的输出:

Importing defaults

*在Javascript中导入*

通常情况下,我们把要导入的东西放在大括号里 import {...}。

创建一个名为client.js 的文件并添加以下代码:

// client.js

const marvel = (hero) => {
  console.log(`Hello, ${hero}!`);
}

const dc = (hero) => {
  console.log(`Bye, ${hero}!`);
}

export {marvel, dc};

client.js文件导出了两个函数。因此,我们可以在app.js 文件中导入这两个函数。

现在,在app.js 文件中添加以下代码:

// app.js

import * as superHeros from './client';

superHeros.marvel('Venom');
superHeros.dc('Wondar Woman');

因此,我们已经导入了所有的模块作为superHeros。

请看输出:

➜  es git:(master) ✗ node start
Hello, Venom!
Bye, Wondar Woman!
➜  es git:(master) ✗

Javascript中的动态导入

import关键字可以被称为动态导入模块的函数。当使用这种方式时,它会返回承诺。让我们看看这个例子:

// app.js

let app = await import('./data');
console.log(`The addition is: ${add(2, 3)}`);

它将给出同样的输出。在上面的代码中,我们使用了ES7的async-await功能。

如果你是这方面的新手,那么请看这篇文章

当你希望有条件地或按需地加载模块时,动态导入很有帮助。

静态形式更适合初始加载依赖关系,可以更容易从静态分析工具和树状摇动中受益。

修复:不能在模块外使用导入语句

这是什么情况?不能 在模块外使用导入语句的错误,以及如何修复它。

这是一个未捕获的语法错误。造成这个问题是因为导入语句是ES6语法,而node.js理解的是require模块 语法。因此,首先,你需要将你的代码编译为ES5,然后以这种方式运行node服务器文件,就可以正常工作了。

现在所有的主要浏览器都支持ES6模块的原生性!我已经开始了一些简单的测试,你猜怎么着,马上就碰到了问题。

似乎外面很多围绕Javascript Modules的随机讨论实际上是关于Webpack或Babel等产品如何使用Modules架构的,与它在原生JavaScript中的实现方式相比,有一些微妙而关键的区别。

静态导入语句用于导入由另一个模块导出的绑定物。

无论你是否声明,导入的模块都处于严格模式。

import语句不能用于嵌入式脚本,除非该脚本有type="module"。

下面是一个带有类型模块的导入语句的例子。

type = "module"

关于Javascript模块的伟大之处在于,你可以在文件之间导入导出功能。

在任何给定的时间点上,你的主HTML文件至少要有一个脚本标签来加载你的主Javascript文件。你的脚本标签,在这种情况下,必须有等于模块的新类型属性,像这样:

<script src="main.js" type="module"></script>

如果你不包括type="module"YouAll在很多不同的麻烦和错误**,令人难以置信的混乱。

火狐浏览器

SyntaxError: import声明只能出现在模块的顶层

浏览器

未发现的语法错误。意外的标识符

边缘浏览器

SCRIPT1086:SCRIPT1086:模块导入或导出语句在此意外

所以,在你的脚本标签中加入type="模块"

有很多原因会导致上述问题的发生。

例如,你可能在src目录下有一个源文件,而不是在dist目录下的构建文件。

这意味着你在使用未修改/未捆绑状态下的本地源代码,从而导致以下错误。未发现的语法错误。不能在模块外使用导入语句。

你可以通过建立脚本文件和导入它们来解决这个问题。

另一个问题可能是你正在加载使用es6与普通js文件的文件;你应该先编译es6,然后加载文件来解决这个问题。

你可以在脚本标签中加入type=" module",问题就解决了。

Node.js最新版本解决方案

验证你是否安装了最新版本的Node 。如果你最近更新了Node版本,那么-experimental-modules标志就不再需要了。

按照以下任何一个选项来解决这个问题。

在最近的父包.json中添加 "类型":"模块"。

有了这个,所有 .js.mjs 文件都被解释为ES模块。你可以通过使用 .cjs 扩展名将 个别文件理解为CommonJS 。

或者

明确以.mjs为扩展名命名文件。

所有其他文件,如.js,将被解释为CommonJS,如果package.json中没有定义该类型,则默认为CommonJS。

总结

这里是Javascript中所有类型的导入-导出。

导出

在类/函数/...的声明之前。

export [default] class/function/variable ...

独立的导出。

export {x [as y], ...}。

重新导出。

export {x [as y], ...} from "module"
export * from "module" (does not re-export default).
export {default [as y]} from "module" (re-export default)。

导入

从模块中命名的导出。

import {x [as y], ...} from "module"

默认导出。

从 "模块 "导入x "从 "模块 "导入 {default as x}"。

所有的东西。

import \ as obj from "module"

导入模块(其代码运行),但不要将其分配给一个变量。

import "module"。

你可以在MDN上参考更多关于Javascript导入的内容。

所以在这个例子中,我们已经看到了如何使用javascript导入语句、导出语句和动态导入。

这篇文章就讲到这里。