Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

这些 ECMAScript 模块知识,都是我需要知道的 #263

Open
husky-dot opened this issue Sep 8, 2020 · 0 comments
Open

这些 ECMAScript 模块知识,都是我需要知道的 #263

husky-dot opened this issue Sep 8, 2020 · 0 comments

Comments

@husky-dot
Copy link
Owner

作者:Valentino Gagliardi
译者:前端小智
来源:valentinog

点赞再看,微信搜索 【大迁世界】 关注这个没有大厂背景,但有着一股向上积极心态人。本文 GitHub https://github.com/qq449245884/xiaozhi 上已经收录,文章的已分类,也整理了很多我的文档,和教程资料。

ES 模块是什么?

ECMAScript模块(简称ES模块)是一种JavaScript代码重用的机制,于2015年推出,一经推出就受到前端开发者的喜爱。在2015之年,JavaScript 还没有一个代码重用的标准机制。多年来,人们对这方面的规范进行了很多尝试,导致现在有多种模块化的方式。

你可能听说过AMD模块UMD,或CommonJS,这些没有孰优孰劣。最后,在ECMAScript 2015中,ES 模块出现了。

我们现在有了一个“正式的”模块系统。

ES 模块无处不在?

理论上,ES 模块应该在所有JavaScript环境中。实际上,ES 模块的主要应用还是在浏览器上。

2020年5月,Node.js v12.17.0 增加了在不使用标记前提下对ECMAScript模块的支持。 这意味着我们现在可以在Node.js中使用importexport ,而无需任何其他命令行标志。

ECMAScript模块要想在任何JavaScript环境通用,可能还需要很长的路要走,但方向是正确的。

ES 模块是什么样的

ES 模块是一个简单的文件,我们可以在其中声明一个或多个导出。以下面utils.js为例:

// utils.js
export function funcA() {
  return "Hello named export!";
}

export default function funcB() {
  return "Hello default export!";
}

这里有两个导出。

第一个是命名导出,后面是export default,表示为默认导出

假设我们的项目文件夹中有一个名为utils.js的文件,我们可以将这个模块提供的对象导入到另一个文件中。

如何从 ES模块 导入

假设我们在项目文中还有一个Consumer.js的文件。 要导入utils.js公开的函数,我们可以这样做:

// consumer.js
import { funcA } from "./util.js";

这种对应我们的命名导入方式.

如果我们要导入 utils.js 中的默认导出也就是 funcB 方法,我们可以这样做:

// consumer.js
import { funcA } from "./util.js";

当然,我们可以导入同时导入命名和默认的:

// consumer.js
import funcB, { funcA } from "./util.js";

funcB();
funcA();

我们也可以用星号导入整个模块:

import * as myModule from './util.js';

myModule.funcA();
myModule.default();

注意,这里要使用默认到处的方法是使用 default() 而不是 funcB()

从远程模块导入:

import { createStore } from "https://unpkg.com/[email protected]/es/redux.mjs";

const store = createStore(/* do stuff */)

浏览器中的 ES 模块

现代浏览器支持ES模块,但有一些警告。 要使用模块,需要在 script 标签上添加属性 type, 对应值 为 module

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ECMAScript modules in the browser</title>
</head>
<body>
<p id="el">The result is: </p>
</body>
<script type="module">
    import { appendResult } from "./myModule.js";

    const el = document.getElementById("el");
    appendResult(el);
</script>
</html>

myModule.js 内容如下:

export function appendResult(element) {
  const result = Math.random();
  element.innerText += result;
}

动态导入

ES 模块是静态的,这意味着我们不能在运行时更改导入。随着2020年推出的动态导入(dynamic imports),我们可以动态加载代码来响应用户交互(webpack早在ECMAScript 2020推出这个特性之前就提供了动态导入)。

考虑下面的代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Dynamic imports</title>
</head>
<body>
<button id="btn">Load!</button>
</body>
<script src="loader.js"></script>
</html>

再考虑一个带有两个导出的JavaScript模块

// util.js
export function funcA() {
  console.log("Hello named export!");
}

export default function funcB() {
  console.log("Hello default export!");
}

为了动态导入 util.js 模块,我们可以点击按钮在去导入:

/ loader.js
const btn = document.getElementById("btn");

btn.addEventListener("click", () => {
  // loads named export
  import("./util.js").then(({ funcA }) => {
    funcA();
  });
});

这里使用解构的方式,取出**命名导出 ** funcA 方法:

({ funcA }) => {}

ES模块实际上是JavaScript对象:我们可以解构它们的属性以及调用它们的任何公开方法。

要使用动态导入的默认方法,可以这样做

// loader.js
const btn = document.getElementById("btn");

btn.addEventListener("click", () => {
  import("./util.js").then((module) => {
    module.default();
  });
});

当作为一个整体导入一个模块时,我们可以使用它的所有导出

// loader.js
const btn = document.getElementById("btn");

btn.addEventListener("click", () => {
  // loads entire module
  // uses everything
  import("./util.js").then((module) => {
    module.funcA();
    module.default();
  });
});

还有另一种用于动态导入的常见样式,如下所示:

const loadUtil = () => import("./util.js");

const btn = document.getElementById("btn");

btn.addEventListener("click", () => {
  //
});

loadUtil返回的是一个 promise,所以我们可以这样操作

const loadUtil = () => import("./util.js");

const btn = document.getElementById("btn");

btn.addEventListener("click", () => {
  loadUtil().then(module => {
    module.funcA();
    module.default();
  })
})

动态导入看起来不错,但是它们有什么用呢?

使用动态导入,我们可以拆分代码,并只在适当的时候加载重要的代码。在 JavaScript 引入动态导入之前,这种模式是webpack(模块绑定器)独有的。

ReactVue通过动态导入代码拆分来加载响应事件的代码块,比如用户交互或路由更改。

动态导入JSON文件

假设我们项目有一个 person.json 文件,内容如下:

{
  "name": "Jules",
  "age": 43
}

现在,我们需要动态导入该文件以响应某些用户交互。

因为 JSON 文件不是一个方法,所以我们可以使用默认导出方式:

const loadPerson = () => import('./person.json');

const btn = document.getElementById("btn");

btn.addEventListener("click", () => {
  loadPerson().then(module => {
    const { name, age } = module.default;
    console.log(name, age);
  });
});

这里我们使用解构的方式取出 nameage :

const { name, age } = module.default;

动态导入与 async/await

因为 import() 语句返回是一个 Promise,所以我们可以使用 async/await:

const loadUtil = () => import("./util.js");

const btn = document.getElementById("btn");

btn.addEventListener("click", async () => {
  const utilsModule = await loadUtil();
  utilsModule.funcA();
  utilsModule.default();
})

动态导入的名字

使用import()导入模块时,可以按照自己的意愿命名它,但要调用的方法名保持一致:

import("./util.js").then((module) => {
    module.funcA();
    module.default();
  });

或者:

  import("./util.js").then((utilModule) => {
    utilModule.funcA();
    utilModule.default();
  });

原文:https://www.valentinog.com/blog/es-modules/

代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug

文章每周持续更新,可以微信搜索**【大迁世界 】第一时间阅读,回复【福利】**有多份前端视频等着你,本文 GitHub https://github.com/qq449245884/xiaozhi 已经收录,欢迎Star。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant