前言

关于 JavaScript Modular 的多种版本和历史看这篇.

参考:

阮一峰 – Module 的语法

阮一峰 – Module 的加载实现

Export 语法

逐个 export

在想要 export 的 var, function, class 前面加上 export 关键字即可.

export const myVar = "value";
export function myFunction() {}
export class MyClass {}

底部批量 export

const myVar = "abc";
function myFunction() {}
class MyClass {} export { myVar, myFunction, MyClass };

另一种 export 的方式是在底部 export 一个对象, 然后把想 export 的 var, function, class 放进去即可. 推荐使用这种写法, 一目了然, 管理加分.

别名 alias

export { myVar as yourVar };

通过 as 关键字, 替换原本的变量名.

错误语法

export 'value'; // 错误 : 直接 export 值是不可以的, 需要有 variable name
const myVar = 'abc'; // 正确 const myVar = 'abc';
export myVar; // 错误 : 需要一个对象声明 variable name
export { myVar }; // 正确 if(true) {
const myVar = 'abc';
export {myVar}; // 错误 : export 一定要在顶部, 不能在 function 或者 if 里面 export
}

Import 语法

逐个 import

使用 import 关键字, 配上一个对象, 里面声明想使用的 var, function, class 等等, 然后指向一个 js file.

import { myVar, MyClass, myFunction } from "./index2.js";

myFunction();
console.log(myVar);
const myClass = new MyClass();

import 所有内容

把所有内容放入 myModule 对象

import * as myModule from "./index2.js";

myModule.myFunction();
console.log(myModule.myVar);
const myClass = new myModule.MyClass();

别名 alias

import { myVar as yourVar } from "./index2.js";

console.log(yourVar);

import nothing

import "./index2.js";

import 有执行的效果, 所以哪怕没有要使用任何 export 的内容, 也可以使用 import, 单纯为了让 index2.js 执行.

Import, Export 知识点

export, import 的变量是同步

它不是  cache, 这点跟 CommonJS 不同哦.

index2.js

let myVar = "value1";
setTimeout(() => {
myVar = "value2";
}, 1000); export { myVar };

index.js

import { myVar } from "./index2.js";

console.log(myVar); // value1
setTimeout(() => {
console.log(myVar); // value2 (注意: 这里是 value2 哦)
}, 2000);

export, import 的变量是 read-only

这点也和 CommonJS 不同

import { myVar } from "./index2.js";

myVar = "value2"; // Error: Assignment to constant variable.

使用 import * as 依然不能改

import * as myModule from "./index2.js";

myModule.myVar = "value2"; // Error: Cannot assign to read only property 'myVar' of object '[object Module]'

如果值是一个对象, 那可以改它的属性 (但不建议这样做, 很乱)

// index2.js
export const myVar = { name: "Derrick" }; // index.js
import { myVar } from "./index2.js"; myVar.name = "new name"; // ok 的

import 有提升效果

就像 function 一样 (但不建议这样做, 很乱)

console.log(myVar); // ok 的
import { myVar } from "./index2.js";

import multiple time

import 多次也只会执行一次, 它类似单列的效果.

import "./index2.js";
import "./index2.js"; // 并不会多跑一次哦

错误写法

import "./ind" + "ex2.js"; // 不支持动态写法, 因为 ES Module 的概念就是静态的

if (true) {
import 'index2.js'; // import 和 export 一样不能写在 function, if 里面 (除非使用 dynamic import 语法)
}

Export default 语法

基本用法

default 的目的是让 export 的时候省略命名, 好处是 import 的时候可以不需要定义名字. 用例子说明:

// index2.js
const myVar = "value";
export { myVar }; // index.js
import { myVar } from "./index2.js";
console.log(myVar);

index.js 必须知道 "myVar" 这个 name 才能 import 到指定的 variable. 如果使用 default 关键字的话:

// index2.js
const myVar = "value";
export default myVar; // index.js
import whatEverName from "./index2.js";
console.log(whatEverName);

export 的时候使用了 defualt, import 的时候就可以任意命名.

注: import 的时候不需要花括弧哦

default 也就是个别名 alias 而已

上面的写法和下面这个写法是完全等价的

// index2.js
const myVar = "value";
export { myVar as default }; // index.js
import { default as whatEverName } from "./index2.js";
console.log(whatEverName); import * as myModule from "./index2.js";
console.log(myModule.default); // 这样也是可以的

default 可以和普通 export 一起用

// index2.js
const myVar = "value";
function myFunction() {} export default myVar;
export { myFunction }; // index.js
import myDefaultVar, { myFunction } from "./index2.js"; console.log(myDefaultVar);
myFunction();

注: import default 不需要花括弧哦, 其它的就需要.

错误写法

// variable:
// export 'value'; // 错误, 因为没有名字
// export const myVar = 'value'; // 正确, myVar 就是名字
// export default 'value'; // 正确, 因为 default 充当了名字
// export default const myVar = 'value'; // 错误, 因为 default 已经是一个名字了, myVar 又是一个名字. 不允许
// const myVar = "value";
// export default myVar; // 正确, 分开写就可以 // function & class:
// export function (){} // 错误, 因为没有名字
// export class {} // 错误, 因为没有名字
// export function myFunction () {} // 正确, myFunction 就是名字
// export class MyClass {} // 正确, MyClass 就是名字
// export default function() {} // 正确, 因为 default 充当了名字
// export default class {} // 正确, 因为 default 充当了名字
// export default function myFunction() {} // 正确, 因为 myFunction 被忽视了
// export default class MyClass {} // 正确, 因为 MyClass 被忽视了

variable 的部分很好理解. 比较特别的是 function 和 class 的最后 2 个. myFunction 和 myClass 名字被忽视了, 所以语法是 ok 的, 但是同样的情况 variable 的最后一行是不通过的. myVar 没有被忽视.

re-export 语法

有时候只是想再导出一些方法, 就会需要用到 re-export 了. 有点像 extends module 的概念.

// index.js
import { myFunction, myVar, yourVar } from "./index2.js"; console.log([myVar, yourVar]); // index2.js
const yourVar = "yourVar"; export { myVar, myFunction } from "./index3.js";
export { yourVar };
// export * from './index3.js' // export all (注意: 确保不要和当前 module export 撞名字哦, 包括 default 也不能撞哦) // index3.js
const myVar = "myVar";
function myFunction() {}
export { myVar, myFunction };

re-export != import

re-export 并不会把 variable import 到当前模块

export { myVar } from "./index2.js";
console.log(myVar); // 错误

如果当前 module 依赖 variable 那么就需要 import + re-export

import { myVar } from "./index3.js";
const yourVar = "yourVar";
console.log(myVar); // 可以使用 export { yourVar }; // 可以这样 re-export
export { myVar, myFunction } from "./index3.js"; // 也可以继续用这个方式

动态 import()

注: 这个是 es2020 才出的哦, 虽然 es2015 就有 module 了, 但是最好是用 es2020 版本, 它比较完善.

上面讲的 import 都是静态的. 这也是 ES Module 的特色之一. 在编译是就可以知道依赖.

但有时候是需要动态 import 的, 比如有些 module 用户不常用到又很大, 那么就可以做按需加载, lazy load.

static import

import * as module from "./index2.js";
console.log(module.myVar);
console.log(module.default);

dynamic import

import("./index2.js").then(module => {
console.log(module.myVar);
console.log(module.default);
});

使用 import() 关键字, 它会返回 promise

既然它是动态的, 那就可以放到 if, function 里头了, static import 就不行

if (true) {
import * as module from "./index2.js"; // Error: An import declaration can only be used at the top level of a module.
console.log(module.myVar);
console.log(module.default);
} if (true) {
import("./index2.js").then((module) => { // ok 的
console.log(module.myVar);
console.log(module.default);
});
}

HTML 引入

普通的 script 是这样的

<script src="./index.js"></script>

如果 index.js 里面用到了 import / export, 那么它会报错 "Cannot use import statement outside a module".

需要加入 type="module"

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

注: 它同时自带了 defer 的效果哦, (只有 defer 没有 async 效果哦)

Node.js 使用 ES Module

如何使用 CommonJS 看这篇

Node.js 默认是 CommonJS. 如果直接使用 import export 的话会报错 "Cannot use import statement outside a module".

.mjs

解决方法是把带有 ES Module 的 js file 改成 .mjs

// my-module.mjs
export const myVar = "myVar"; // index.mjs
import { myVar } from "./my-module.mjs";
console.log(myVar); // 运行 node index.mjs

.cjs

另一个方法是把默认的 CommonJS 换成 ES Module

到 package.json 添加属性 "type": "module"

把 .mjs 换回 .js 就可以了.

但这个时候如果想使用 CommonJS 的话, 就要把 .js 替换成 .cjs. 它和 .mjs 是一个概念.

ES Module import CommonJS

ES Module 是异步, 预编译的, CommonJS 是 runtime 的. 所以 ES Module 想 import CommonJS 是 ok 的.

// my-module.cjs
exports.myVar = "myVar"; // index.mjs
import { myVar } from "./my-module.cjs"; // 注意: 这个是 cjs 哦
console.log(myVar);

CommonJS require ES Module

反过来就不行了, require mjs 会报错

const myVar = require("./my-module.mjs");

但是可以用 dynamic import()

const myVar = require("./my-module2.cjs");
import("./my-module.mjs").then((m) => console.log(m.myVar));
console.log(myVar);

在一个 .cjs 里面用了 require 同时也用 dynamic import(). 这个 .cjs 虽然用了 import 但它任然是属于 CJS 哦.

JavaScript – ES Module的更多相关文章

  1. JS JavaScript模块化(ES Module/CommonJS/AMD/CMD)

    前言 前端开发中,起初只要在script标签中嵌入几十上百行代码就能实现一些基本的交互效果,后来js得到重视,应用也广泛起来了, jQuery,Ajax,Node.Js,MVC,MVVM等的助力也使得 ...

  2. UMD、CommonJS、ES Module、AMD、CMD模块的写法

    AMD异步模块规范 RequireJS就是AMD的一个典型的实现. 以下是一个只依赖与jQuery的模块代码: // foo.js define(['jquery'], function($){ // ...

  3. 彻底掌握 Commonjs 和 Es Module

    目录 Commonjs commonjs 实现原理 require 文件加载流程 require 模块引入与处理 require 加载原理 require 避免重复加载 require 避免循环引用 ...

  4. javascript闭包(Module模式)的用途和高级使用方式

    javascript闭包(Module模式)的用途和高级使用方式 javascript闭包的用途:1. 匿名自执行函数:或者可以理解为,避免污染全局变量2. 缓存:源于闭包的核心特性便是保存状态,应用 ...

  5. 前端模块化之ES Module

    一.概述 之前提到的几种模块化规范:CommonJS.AMD.CMD都是社区提出的.ES 2015在语言层面上实现了模块功能,且实现简单,可以替代CommonJS和AMD规范,成为在服务器和浏览器通用 ...

  6. 使用 ES Module 的正确姿势

    前面我们在深入理解 ES Module 中详细介绍过 ES Module 的工作原理.目前,ES Module 已经在逐步得到各大浏览器厂商以及 NodeJS 的原生支持.像 vite 等新一代的构建 ...

  7. JS 模块化- 05 ES Module & 4 大规范总结

    1 ES Module 规范 ES Module 是目前使用较多的模块化规范,在 Vue.React 中大量使用,大家应该非常熟悉.TypeScript 中的模块化与 ES 类似. 1.1 导出模块 ...

  8. JavaScript ES6 module 模块

    在使用JavaScript开发大型项目时,模块开发概念是一个必须考虑的问题.其目的就是通过命名空间对各类业务对象进行一定的封装,防止命名冲突. 本篇着重介绍ES6 module中的export和imp ...

  9. JavaScript ES 模块:现代化前端编程必备技能

    自从 ES 模块被添加到规范中后,JavaScript 中的模块就更加简单了.模块按文件分开,异步加载.导出是用 export 关键字定义的:值可以用 import 关键字导入. 虽然导入和导出单个值 ...

  10. ES module 实现方式

    随着js社区不断发展,js功能更加强大,细数js的几种 module 方式. 整理了七种模块化方式 1.作为新手,练习小的demo,比较喜欢的方式.不适合大的项目. <!--html--> ...

随机推荐

  1. VBA | 统计数组某元素出现的次数,适用于一维、二维数组

    很简单的需求,但是中文网络上基本都是循环的方法,经过查找下面的方法很有效.为了方便用户的使用,进行了如下的整改. 1 Sub Statistics_Number_of_occurrences_test ...

  2. <script> 和 <script setup> 的一些主要差别

    <script setup> 是 Vue 3 中的新特性,它是一种简化和更具声明性的语法,用于编写组件的逻辑部分.相比之下,<script> 是 Vue 2 中常用的编写组件逻 ...

  3. oeasy 教您玩转 linux 010400 总结 summary

    ###### 上一部分我们都讲了什么?*   各种gui*   qt和gdk两个开源工具跨平台开发库*   发行版和gui之间的关系###### 我们一起来回顾一下整个学习过程*   我们从零开始*  ...

  4. 企业级环境部署:在 Linux 服务器上如何搭建和部署 Python 环境?

    在大部分企业里,自动化测试框架落地都肯定会集成到Jenkins服务器上做持续集成测试,自动构建以及发送结果到邮箱,实现真正的无人值守测试. 不过Jenkins搭建一般都会部署在公司的服务器上,不会在私 ...

  5. 【JavaScript高级02】JavaScript第一大神兽:原型和原型链

    1,函数中的prototype属性 每个函数都会有一个属性prototy,该属性默认指向一个空Object对象,而这个空的Object对象被称之为原型对象. <script > conso ...

  6. 2024NOI联合省选游记

    人生当中成功只是一时的,而失败却是主旋律. 不太好的的阅读体验 本文作者:xxxalq 所谓游记,顾名思义就是指游玩所记,所以重点在玩而不在省选. 由于没有参加 \(\text{NOIP}\),导致我 ...

  7. 使用 Doxygen 来生成 Box2d 的 API 文档

    对于 Doxygen 以前只听别人说过,而现在使用它也是一个偶然,缘分吧.前两天看 box2d 的官方 sdk 中,发现他有用户手册却没有说明,只是留下了一个 Doxygen 的文件.事情告一段落,然 ...

  8. 家中局域网搭建nas后的一些体验 —— NAS的速率究竟如何计算

    NAS局域网,使用的路由器的有线端口为1000Mbps,无线WiFi速率860Mbps,不过由于不知道是不是因为电脑WiFi接收器型号老旧还是路由器WiFi协议或天线老旧(电脑和路由器均不支持WiFi ...

  9. OneFlow是否真的实现了单机代码无侵害的运行在分布式集群上?

    答案: 不是,但也是. 严格意义上来说,不是. 因为技术OneFlow的代码,要从单机改到分布式,也需要改配置,需要给所有的变量设置具体的全局存储还是局部存储,如果局部存储又应该如何划分,等等,这些其 ...

  10. 【转载】 tf.image.sample_distorted_bounding_box (为图像生成单个随机变形的边界框)

    原文地址: https://blog.csdn.net/tz_zs/article/details/77920116 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上 ...