ESModule
ESModule基本使用
JavaScript没有模块化一直是它的痛点font>,所以才会产生我们前面学习的社区规范:CommonJS、AMD、CMD等,所以在ECMA推出自己的模块化系统时,大家也是非常兴奋。
ES Module和CommonJS的模块化有一些不同之处:
- 一方面它使用了import和export关键字;
- 另一方面它采用编译期的静态分析,并且也加入了动态引用的方式;
ES Module模块采用export和import关键字来实现模块化:
- export负责将模块内的内容导出;
- import负责从其他模块导入内容;
了解:采用ES Module将自动采用严格模式:use strict
注意: 如果直接在浏览器中运行代码,会报错, 这个报错在MDN上面有给出解释:
- https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Modules
- 你需要注意本地测试 — 如果你通过本地加载Html 文件 (比如一个 file:// 路径的文件), 你将会遇到 CORS 错误,因为Javascript 模块安全性需要;
- 你需要通过一个服务器来测试;
我这里使用的VSCode插件:Live Server
在代码中看一下ES Module的基本使用吧:
- script标签引入需要加上
type='module'
, 表示是一个模块
<script src="./main.js" type="module"></script>
<script src="./foo.js" type="module"></script>
- 注意: 导出的大括号不是一个对象, 他是一个固定的格式, 导出写的是标识符, 不是对象的增强写法;
- 导出格式
export { 标识符1, 标识符2, ... }
const name = "kaisa"
const age = 18
function running() {
console.log("running~")
}
// 导出
export {
name,
age,
running
}
- main中导入文件
import { name, age, running } from "./foo.js";
console.log(name)
console.log(age)
running()
export其他用法
export关键字将一个模块中的变量、函数、类等导出;
我们希望将其他中内容全部导出,它可以有如下的方式:
方式一(刚刚讲过):将所有需要导出的标识符,放到export后面的 {}中
-
注意:这里的 {}里面不是ES6的对象字面量的增强写法,{}也不是表示一个对象的;
-
所以: export {name: name},是错误的写法;
方式二: 导出时给标识符起一个别名
- 通过as关键字起别名
- 假如我们想要导出一个name属性, 而导入的地方已经定义过name属性, 那么我们可以为name属性取一个别名
export {
// 导出时给fname取别名
name as fname,
age,
running
}
方式三: 在语句声明的前面直接加上export关键字
- 这种方式适用于, 当我们定义变量时, 就确定要导出的情况
- 这种方式不可以取别名
// 定义变量的时候就导出
export const address = "成都市"
import其他用法
import关键字负责从另外一个模块中导入内容
导入内容的方式也有多种:
方式一(刚刚讲过):import {标识符列表} from ‘模块’;
- 注意:这里的{}也不是一个对象,里面只是存放导入的标识符列表内容;
方式二:导入时给标识符起别名
- 通过as关键字起别名
// 导入的时候取别名
import { name as fname, age, running, address } from "./foo.js";
方式三:通过 * 将整个模块全部导入, 并给整个模块取个别名
// 导入整个模块, 并取名为foo
import * as foo from "./foo.js"
// 使用模块内容
console.log(foo.name) // kaisa
console.log(foo.age) // 18
foo.running() // running~
console.log(foo.address) // address
export和import结合
补充:export和import可以结合使用
为什么要这样做呢?
-
在开发和封装一个功能库时,通常我们希望将暴露的所有接口放到一个文件中;
-
这样方便指定统一的接口规范,也方便阅读;
-
这个时候,我们就可以使用export和import结合使用;
使用方法:
- 例如想要从另一个文件导出, 再导出暴露出去
// 从其他文件导入
import { name, age, running, address } from "./foo.js"
// 导出
export {
name,
age,
running,
address
}
- 优化方式一: 可以结合起来使用, 这样优化阅读性比较好(推荐)
export { name, age, running, address } from "./foo.js"
- 优化方式二: 阅读性比较差, 代码更简介
export * from "./foo.js"
default用法
前面我们学习的导出功能都是有名字的导出(named exports):
-
在导出export时指定了名字;
-
在导入import时需要知道具体的名字;
还有一种导出叫做默认导出(default export)
-
默认导出export时可以不需要指定名字;
-
在导入时不需要使用 {},并且可以自己来指定名字;
-
它也方便我们和现有的CommonJS等规范相互操作;
演示代码:
- 默认导出
export default function() {
console.log("foo函数~")
}
- 导入时, 由于默认导出是没有名字的, 所以我们可以自定义名称
// 导入可自定义名, 且不需要加大括号{}
import aaa from "./foo.js"
aaa()
注意:在一个模块中,只能有一个默认导出(default export);
import函数
通过import加载一个模块,是不可以在其放到逻辑代码中的,比如:
let flag = true
if (flag) {
// 错误示范
import { name, age, running } from "./foo.js"
}
为什么会出现这个情况呢?
-
这是因为ES Module在被JS引擎解析时,就必须知道它的依赖关系;
-
由于这个时候js代码没有任何的运行,所以无法在进行类似于if判断中根据代码的执行情况;
-
甚至拼接路径的写法也是错误的:因为我们必须到运行时能确定path的值
但是某些情况下,我们确确实实希望动态的根据条件判断, 来决定示范加载某一个模块:
- 如果根据不懂的条件,动态来选择加载模块的路径;
- 这个时候我们需要使用 import() 函数来动态加载;
- import函数中导入是异步的, 不会阻塞代码, 返回一个Promise,可以通过then获取结果;
演示代码:
let flag = true
if (flag) {
// 会返回一个Promise
import("./foo.js").then(res => {
// 在then方法中获取结果
console.log(res.name)
console.log(res.age)
res.running()
})
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/120099.html