JS Module 的加载实现

发布于 2024-11-05 01:19:38 字数 2094 浏览 1 评论 0

加载规则

浏览器加载 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

0 文章
0 评论
23 人气
更多

推荐作者

emdigitizer10

文章 0 评论 0

残龙傲雪

文章 0 评论 0

奢望

文章 0 评论 0

微信用户

文章 0 评论 0

又爬满兰若

文章 0 评论 0

独孤求败

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文