JS Module 的加载实现
加载规则
浏览器加载 ES6 模块,也使用 script 标签,但是要加入 type="module"属性。
<script type="module" src="./foo.js"></script>
等同于打开了 defer 属性(多个也是一样,dom 加载完毕,按顺序执行)
<script type="module" src="./foo.js" defer></script>
async 属性也可以打开,这时只要加载完成,渲染引擎就会中断渲染立即执行。执行完成后,再恢复渲染(不按顺序)
<script type="module" src="./foo.js" async></script>
也允许内嵌在网页中
<script type="module">
import utils from "./utils.js"
// other code
</script>
外部的模块脚本
import utils from 'https://example.com/js/utils.js'
const x = 1
console.log(x === window.x) //false
console.log(this === undefined) // true
注意点
- 代码是在模块作用域之中运行,而不是在全局作用域运行。模块内部的顶层变量,外部不可见。
- 模块脚本自动采用严格模式,不管有没有声明 use strict。
- 模块之中,可以使用 import 命令加载其他模块(.js 后缀不可省略,需要提供绝对 URL 或相对 URL),也可以使用 export 命令输出对外接口。
- 模块之中,顶层的 this 关键字返回 undefined,而不是指向 window。也就是说,在模块顶层使用 this 关键字,是无意义的。
- 同一个模块如果加载多次,将只执行一次。
//侦测当前代码是否在 ES6 模块之中。
const isNotModuleScript = this !== undefined
ES6 模块与 CommonJS 模块的差异
两个重大差异
- CommonJS 模块输出的是一个值的浅拷贝,ES6 模块输出的是值的引用
- CommonJS 模块是运行时加载,ES6 模块是编译时输出接口
第二个差异是因为 CommonJS 加载的是一个对象(即 module.exports 属性),该对象只有在脚本运行完才会生成。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。
ES6 export 通过接口,输出的是同一个值。不同的脚本加载这个接口,得到的都是同样的实例。
// mod.js
function C() {
this.sum = 0
this.add = function () {
this.sum += 1
}
this.show = function () {
console.log(this.sum)
}
}
export let c = new C()
// x.js
import {c} from './mod'
c.add()
// y.js
import {c} from './mod'
c.show()
// main.js
import './x'
import './y'
$ babel-node main.js
1
x.js 和 y.js 加载的都是 C 的同一个实例。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: JS 变量的解构赋值
下一篇: TypeScript 常见问题
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论