JavaScript ES6 模块
在本教程中,您将了解 ES6 模块 以及如何从模块中导出变量、函数和类,并在其他模块中使用它们。
ES6 模块是一个仅在严格模式执行的 JavaScript 文件。这意味着模块中声明的任何变量或函数都不会自动添加到全局作用域。
在 Web 浏览器运行模块
首先,创建一个 message.js
文件并添加以下代码:
export let message = 'ES6 Modules';
message.js
是包含 message
变量的 ES6 模块。export
语句将 message
变量公开给其他模块。
其次,创建另一个新文件 app.js
使用 message.js
模块。app.js
模块创建一个新的 h1
元素并将追加到 HTML 页面。import
语句从 message.js
模块导入 message
变量。
import { message } from './message.js'
const h1 = document.createElement('h1');
h1.textContent = message
document.body.appendChild(h1)
最后,创建一个 HTML 页面使用 app.js
模块:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>ES6 Modules</title>
</head>
<body>
<script type="module" src="./app.js"></script>
</body>
</html>
请注意,我们在 <script> 标签中使用 type="module"
来加载 app.js
模块。如果您在 Web 浏览器查看该页面,您将看到以下页面:
下面,让我们更详细地理解导出 export
和导入 import
语句。
export
要导出变量、函数或类,请将 export
关键字放在其前面,如下所示:
// log.js
export let message = 'Hi';
export function getMessage() {
return message;
}
export function setMessage(msg) {
message = msg;
}
export class Logger {
}
在这个例子中,我们有一个带有变量、两个函数和一个类的模块 log.js
。我们使用 export
关键字导出模块的所有。
请注意,export
关键字要求函数或类具有要导出的名称。您不能使用此语法导出匿名函数或类。
JavaScript 允许您先定义变量、函数或类,然后再将其导出,如下所示:
// foo.js
function foo() {
console.log('foo');
}
function bar() {
console.log('bar');
}
export foo;
在这个例子中,我们先定义 foo()
函数,然后导出它。由于我们没有导出 bar()
函数,因此我们无法在其他模块中访问 bar()
函数。bar()
函数在模块外是不可访问的,或者我们说它是私有的。
导入
一旦你定义一个带有导出的模块,你就可以使用 import
关键字访问另一个模块导出的变量、函数和类。下面是 import
语法形式:
import { what, ever } from './other_module.js';
在这个语法中:
首先,在花括号内指定要导入的内容,这称为绑定。
然后,从中指定的模块导入绑定。
请注意,当您从模块导入绑定时,绑定的行为就像使用 const 定义的一样。这意味着您不能拥有另一个具有相同名称的标识符或更改绑定的值。
请阅读以下示例:
// greeting.js
export let message = 'Hi';
export function setMessage(msg) {
message = msg;
}
当你导入 message
变量和 setMessage()
函数时,你可以使用 setMessage()
函数来改变 message
变量的值,如下所示:
// app.js
import {message, setMessage } from './greeting.js';
console.log(message); // 'Hi'
setMessage('Hello');
console.log(message); // 'Hello'
但是,您不能直接更改 message
变量的值。以下表达式会抛出错误:
message = 'Hallo'; // error
在背后,当您调用 setMessage()
函数时。JavaScript 返回 greeting.js
模块并执行其中的代码并更改 message
变量。然后更改会自动反映在导入的 message
绑定。
在 app.js
的 message
绑定是 message
变量导出的本地名称,所以 message
变量在 app.js
和 greeting.js
模块是不一样的。
导入单个绑定
假设您有一个包含以下变量的 foo
模块:
// foo.js
export foo = 10;
然后,在另一个模块中,您可以重用 foo
变量:
// app.js
import { foo } from './foo.js';
console.log(foo); // 10;
但是,您不能更改 foo
的值。如果您尝试这样做,JavaScript 引擎将会抛出错误消息:
foo = 20; // throws an error
导入多个绑定
假设您有如下 cal.js
模块:
// cal.js
export let a = 10,
b = 20,
result = 0;
export function sum() {
result = a + b;
return result;
}
export function multiply() {
result = a * b;
return result;
}
而你想从 cal.js
导入这些绑定,你可以显式列出它们,如下所示:
import {a, b, result, sum, multiply } from './cal.js';
sum();
console.log(result); // 30
multiply();
console.log(result); // 200
将整个模块作为对象导入
要将模块中的所有内容作为单个对象导入,请使用星号 *
,如下所示:
import * as cal from './cal.js';
在此示例中,我们将 cal.js
模块中的所有绑定作为 cal
对象导入。在这种情况下,所有绑定都成为 cal
对象的属性,因此您可以按以下方式访问它们:
cal.a;
cal.b;
cal.sum();
这种导入方式称为命名空间导入。
重要的是要记住,即使导入多次,导入的模块也只会执行一次。请阅读下面的例子:
import { a } from './cal.js';
import { b } from './cal.js';
import {result} from './cal.js';
在第一条 import
语句之后,cal.js
模块被执行并加载到内存,每当被后续 import
语句引用时,它就会被重用。
import 和 export 声明的限制
请注意,您必须在其他语句和函数的外部使用 import
或者 export
语句,否则会导致语法错误。
下面的示例会导致 SyntaxError
:
if( requiredSum ) {
export sum;
}
因为我们使用 export
语句在 if
语句里面。同样, 下面的 import
语句也会导致SyntaxError
:
function importSum() {
import {sum} from './cal.js';
}
因为我们在函数内部使用 import
语句。错误的原因是 JavaScript 必须确定将导出和导入的内容。
请注意,ES2020 引入类函数对象 import(),它允许您动态导入模块。
导入与导出的别名 as关键词
JavaScript 允许您在导出和导入时变量、函数或类时创建别名。请阅读以下 math.js
模块:
// math.js
function add( a, b ) {
return a + b;
}
export { add as sum };
在此示例中,我们没有导出函数 add()
,而是使用 as
关键字为 add()
函数分配给别名 sum
。
因此,当您从 math.js
模块导入函数时,您必须改用 sum
:
import { sum } from './math.js';
如果你想在导入时使用不同的名称,你可以使用 as
关键字如下:
import {sum as total} from './math.js';
重新导出
可以导出已导入的绑定。这称为重新导出。例如:
import { sum } from './math.js';
export { sum };
在这个例子中,我们从 math.js
模块导入 sum
并重新导出它。下面的语句与上面的语句等价:
export {sum} from './math.js';
如果您想在重新导出之前重命名绑定,请使用关键字 as
。以下示例从 math.js
模块导入 sum
并将其重新导出为 add
。
export { sum as add } from './math.js';
如果要从另一个模块导出所有绑定,可以使用星号 * :
export * from './cal.js';
无绑定导入
有时,您希望开发一个不导出任何内容的模块,例如,您可能希望向 Array 等内置对象添加方法。
// array.js
if (!Array.prototype.contain) {
Array.prototype.contain = function(e) {
// contain implementation
// ...
}
}
现在,您可以在没有任何绑定的情况下导入模块,并使用 array.js
模块中定义的 contain()
方法,如下所示:
import './array.js';
[1,2,3].contain(2); // true
默认导出
一个模块只能有一个默认导出。默认导出更容易导入。模块的默认值可以是变量、函数或类。
以下是带有默认导出的 sort.js
模块。
// sort.js
export default function(arr) {
// sorting here
}
请注意,您不需要指定函数的名称,因为模块代表函数名称。
import sort from sort.js;
sort([2,1,3]);
如您所见,标识符 sort
代表 sort.js
模块的默认函数。请注意,我们没有在标识符 sort
周围使用花括号 {}
。
让我们更改 sort.js
模块包含默认导出和非默认导出:
// sort.js
export default function(arr) {
// sorting here
}
export function heapSort(arr) {
// heapsort
}
要导入默认和非默认绑定,您可以在 import
关键字后使用以下规则指定绑定列表:
默认绑定必须首先出现。
非默认绑定必须用花括号括起来。
请阅读以下示例:
import sort, {heapSort} from './sort.js';
sort([2,1,3]);
heapSort([3,1,2]);
要重命名默认导出,您还可以使用 as
关键字,如下所示:
import { default as quicksort, heapSort} from './sort.js';
结论
在本教程中,您了解 ES6 模块以及如何从一个模块导出绑定并将它们导入另一个模块。
如果您有任何问题或反馈,请随时发表评论。点击下方阅读原文获取更好排版格式与文章参考引用。