JavaScript模块化历程(二)

4.模块化标准规范(ES Modules)

ES6 提供的模块化方案叫做 ES Module,简称 esm,现在我开始接触的基本就是这种规范了,写nodejs的时候,偶尔有些第三方框架还是使用的commonJS规范

4.1 如何使用ES6规范

浏览器环境

正常情况下,我们在html中直接可以使用script标签引入我们的js文件

	<script src="./main.js"></script>
	<!-- <script type="application/javascript" src="./main.js"></script> -->

script 标签有一个 type 属性,默认情况为:application/javascript。所以大多数情况都简写了。但是在 ES Module 中,为了告诉浏览器我们是用的 ES Module,需要修改 type属性为 module

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

NodeJs环境

方式一: .mjs,就是将js文件的后缀名改成.mjs
方式二: 配置项目的 package.json 中的 type 属性为 module

注意:

  • NodeJs的8.9之后的版本,就开始支持 ES6了 ,但是在 13.2 版本之后才开启 默认支持运行 ES Module。所以使用版本在 8.9~13.2 之间的 NodeJs ,执行 ES Module 的 js文件。需要添加配置项 --experimental-modules,开启 默认关闭的 ES Module 支持。

  • 上面是我在文章中看到的,我的理解是只要node版本在13.2以上,不按照上面2种方式也能使用ES 6标准,但是实际操作不行,我的版本是16.18.0,后面还是使用方式二npm init

4.2 严格模式

Es Module 第一个特点:默认开启了严格模式。即便你没有在文件的开头添加 use strict

主要有以下限制:

  1. 变量必须声明后再使用
  2. 函数的参数不能有同名属性,否则报错
  3. 不能使用 with 语句
  4. 不能对只读属性赋值,否则报错
  5. 不能使用前缀 0 表示八进制数,否则报错
  6. 不能删除不可删除的属性,否则报错
  7. 不能删除变量 delete prop,会报错,只能删除属性 delete global[prop]
  8. eval 不会在它的外层作用域引入变量
  9. eval 和 arguments 不能被重新赋值
  10. arguments 不会自动反映函数参数的变化,这个还不理解
  11. 不能使用 arguments.callee
  12. 不能使用 arguments.caller
  13. 禁止 this 指向全局对象
  14. 不能使用 fn.caller 和 fn.arguments 获取函数调用的堆栈
  15. 增加了保留字(比如 protected、static 和 interface)
4.3 实际使用
// mian.js
// 可以用*号全部导入 并起别名
import * as student from './student.js'

var studentScore = student.score();
student.skills[0]().then((message) => console.log(message));
console.log(studentScore)
// student.js
// 在没有别的处理的情况下 需要加后缀 .js
// 具体跟搜索有关 后期需要再了解
import { make_food } from "./cook.js";

var maths = 80;
var chinese = 90;
var skills = [make_food];
function score() {
    return maths + chinese;
}
// 批量导出
export { skills, score }
// cook.js
var name = "煮饭";
// 单独导出
export function make_food() {
    return new Promise(function (resolve, reject) {
        setTimeout(() => {
            resolve("煮好饭了")
        }, 1000);
    })
}

package.json

{
  "name": "es6model",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "type": "module",
  "scripts": {
    "test": "node ./main.js"
  },
  "author": "",
  "license": "ISC"
}

注意事项

  1. import 的变量是只读的
  2. import 的变量实际上是对原本模块中变量的引用,也就是说改变原模块变量值,引入的变量值也会改变
  3. 和 export 同理, import 语句不允许放在块级作用域中使用,会直接报错;
  4. 由于ES Module是静态编译,所以 import会被提升到最顶部执行 ;
  5. import 的执行逻辑 优先深度遍历,先子后父,也就是说,会先将一个文件import执行到底,我就不写了,借用博主的代码了,交叉引用的情况也要也要先把子模块全部加载完先
  6. 多次重复执行同一句 import 语句,只会执行一次;
// 第五条的测试
// a.mjs
console.log('a开始执行啦')
// 按理来说上面是要先执行 但是 import会提升
import { say } from './b.mjs'
import { edit } from './c.mjs'
export var a = 1
console.log('a结束了')

// b.mjs
console.log('b开始执行啦')
export function say() {
    console.log('开始说话')
}
import { a } from './a.mjs'
// b中又引用到a 但是这个时候b都还没加载完,所以a模块肯定还没加载完 那么a变量就是个undefined
console.log(a, '----我在这里输出的')
console.log('b结束了')

// c.mjs
console.log('c开始执行啦')
export function edit() {
    console.log('开始编辑')
}
console.log('c结束了')

// main.mjs
import { a } from './a.mjs'

// b开始执行啦
// undefined ----我在这里输出的
// b结束了
// c开始执行啦
// c结束了
// a开始执行啦
// a结束了
4.4 默认导出

为什么 export default 不使用 var 声明一个变量导出呢?
原因是 export default 可以看做就是输出一个叫做 default 的变量或方法,然后系统允许你为它取任意名字。

/* 模拟 default*/
var a = 1
export {a as default}
4.5 加载文件的顺序
  1. 默认情况

默认情况下,浏览器是同步加载 JavaScript 脚本,即渲染引擎遇到<script>标签就会停下来,等到执行完脚本,再继续向下渲染。如果是外部脚本,还必须加入脚本下载的时间。

2.异步加载

添加属性,defer 或者 async,都会开启异步加载
defer与async的区别是:

  • defer要等到整个页面在内存中正常渲染结束(DOM 结构完全生成,以及其他脚本执行完成),才会执行;
  • async一旦下载完,渲染引擎就会中断渲染,执行这个脚本以后,再继续渲染。
    一句话,defer是“渲染完再执行”async是“下载完就执行”

注意:
另外,如果有多个defer脚本,会按照它们在页面出现的顺序加载,而多个async脚本是不能保证加载顺序的。

  1. 加载文件的逻辑
<script src="xxx.js" defer></script>
<script src="xxx.js" async></script>
  1. <script type="module" src="./foo.js"></script> 加载文件的逻辑

所以 <script type="module" src="./foo.js"></script> 可以理解为,异步加载 ./foo.js 文件,等页面渲染完毕之后再开始执行我们的脚本。

<script type="module" src="./foo.js"></script>
<!-- 等同于 -->
<script type="module" src="./foo.js" defer></script>

参考文章

再苦再累也必须要弄懂的:ES6的ES Module

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值