前端JavaScript模块化解析之ESModule用法示例
作者:果壳~
ES Module是ECMAScript 2015引入的模块化规范,通过export和import关键字实现模块的导入导出,这篇文章主要介绍了前端JavaScript模块化解析之ESModule用法的相关资料,需要的朋友可以参考下
基本介绍
- JavaScript没有模块化一直是它的痛点,所以才会产生我们前面学习的社区规范:
CommonJS
、AMD
、CMD
等
所以在ES推出自己的模块化系统时,大家也是兴奋异常。 - ES Module和CommonJS的模块化有一些不同之处
- 一方面它使用了import和export关键字:
- 另一方面它采用编译期的静态分析,并且也加入了动态引用的方式
- ES Module模块采用export和import关键字来实现模块化
- export负责将模块内的内容导出,
- import负责从其他模块导入内容;
- 了解:采用ES Module将自动采用严格模式:use strict
基本使用
// foo.js export const name = "why" export const age = "18"
// main.js import {name,age} from "./foo.js" console.log(name) console.log(age)
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <!--这里必须设置 type="module" 否则浏览是无法识别的--> <script src="main.js" type="module"></script> </body> </html>
让模块化生效的两个前提条件
- script标签要加上 type=“module”
- index.html的访问必须是以服务器的方式访问。也就是访问协议必须是
http
或者https
直接本地文件打开file://
这个协议是不支持的
导入导出方式3种
// foo.js // 导出方式 // 1. 第一种方式: export 声明语句 export const name = "why" export const age = "18" export function foo(){ console.log("foo function") } export class Person {}
// 2. 第二种: export 导出 和 声明分开 const name = "why" const age = "18" function foo(){ console.log("foo function") } export { name, age, foo }
// 3. 第三种方式:第二种导出时起别名 const name = "why" const age = "18" function foo(){ console.log("foo function") } export { name as fName, age as fAge, foo as fFoo }
导入方式
// 导入方式 // 1.导入方式1:普通导入 import {name,age,foo,Person} from "./foo.js" // 2.导入方式二:起别名 import {name as fName,age as fAge,foo as fFoo} from "./foo.js" // 3.导入方式三:将所有哦的内容放到一个标识符中 import * as foo from "./foo.js" console.log(foo.name) console.log(foo.age) console.log(name) console.log(age)
结合使用
当我们某个目录下有很多js文件,导出了很多工具方法如下
// utils/math.js function add(a,b){ return a+b; } function sub(a,b){ return a-b } export { add, sub }
// utils/format.js function timeFormat(){ return "2222-12-12" } function priceFormat(){ return "222.22" } export { timeFormat, priceFormat }
然后在main.js中引入这些模块的函数,代码会变的很麻烦如下
// main.js import {add,sub} from "./utils/math.js" import {timeFormat,priceFormat} from './format.js'
因此一般在utils
目录下会统一定义一个index.js
用来将该目录下的所有需要导出的变量进行一个统一导出。如下
这样mian.js
就可以只导入utils/index.js
即可
// utils/index.js // 导出方式一 import {add,sub} from './math.js' import {timeFormat,priceFormat} from './format.js' export { add, sub, timeFormat, priceFormat }
导出方式一还是显得太复杂,可以结合使用
// utils/index.js // 导出方式二: export {add,sub} from './math.js' export {timeFormat,priceFormat} from './format.js' // 如果要全部导出可如下写法 // 导出方式三: export * from './math.js' export * from './format.js'
default用法
当写的某一个变量,是非常常用的时候,可以使用默认导出。默认导出的方式如下
// foo.js const name = "zxh" const age = 18 const foo = 'foo value' // 1.默认导出的方式一: export { name, age, foo as default } // 2.默认导出的方式二:常见 export default foo // 注意默认导出只能有一个
main.js
在导入默认导出的变量时 如下使用
// 不用进行结构,可自定义接收的变量名 实际上是将 foo.js中的 foo赋值到aaa上 import aaa from './foo.js' console.log(aaa)
import函数
如下代码,在执行的时候是同步执行的,
首先浏览会先将要导入的文件下载下来,进行解析,然后才会执行后续的代码。
import {name,age,foo} from './foo.js' console.log("导入的代码没有解析完之前,后续的代码是不会运行的")
如果希望异步执行:比如页面初始化的时候并不需要用到导出的函数,只是在特定时候才需要使用。那么就可以使用import函数来进行异步执行
import("./foo.js").then(res=>{ console.log("res:",res.name) }) console.log("main.js 执行成功")
// 查看控制台输出,可以看出是异步执行 main.js 执行成功 res:zxh
ES Module的解析流程
具体流程省略
导入的变量无法,导入方无法修改
需要重点提醒一下:导出的变量,是不允许在导入端被修改的
如下
// foo.js export let name = "zifeiyu"
import {name} from "./foo.js" // 这里修改是会报错的 name = 333
// 控制台报错 Uncaught TypeError: Assignment to constant variable. at main.js:3:6
导出的变量,只能由导出方进行修改
// foo.js export let name = "zifeiyu" setTimeout(() => { name = "Kobe" },100)
// main.js import {name} from "./foo.js" console.log(name) setTimeout(()=>{ console.log(name) },2000)
可以看到控制台输出,说明导出方可以修改这个值
zifeiyu Kobe
如果确实想在导入这边对导出的值进行修改,可以自定义set回调函数
// foo.js export let name = "zxh" export function setName(a){ name = a }
import {name,setName} from "./foo.js" console.log(name) setName(3333333) console.log(name)
CommonJS和ESModule相互引用
解释一下:
- 模块A通过commonJS进行导出,然后模块B通过ESModule的方式进行导入。
- 模块C通过ESModule的方式进行导出,然后模块B通过commonJS的方式进行导入。
能否实现呢?
得分情况
- 浏览器:不能实现,因为默认不支持
CommonJS
- node环境下:分情况
- 之前的node版本,只支持
CommonJS
- 现在node版本逐渐在转用
ESModule
- 之前的node版本,只支持
- 正常开发环境
webpack
: 可以使用
实验一下
# 在一个干净的目录下 # 1.通过npm帮我们初始化一下项目,也就是生成 package.json npm init # 2.要使用webpack 需要安装 webpack 和 webpack-cli npm install webpack webpack-cli -D # 3.新建目录src,因为webpack默认的打包入库是 src/index.js
编写几个js进行互相引用
这边案例是打算
- foo.js 通过commonjs导出
- bar.js 通过ESmodule导出
- index.js
- 通过ESmodule 导入
foo.js
- 通过commonjs导入
bar.js
- 通过ESmodule 导入
代码如下
// src/foo.js const fooName = "foo" const fooAge = 18 // commonjs导出 module.exports = { fooName, fooAge }
// src/bar.js const barName = "foo" const barAge = 18 // esmodule导出 export{ barName, barAge }
// src/index.js es module import { fooName, fooAge } from "./foo" console.log(fooName, fooAge) // commonjs 导入 const {barName,barAge} = require('./bar') console.log(barName, barAge)
# 打包 会在当前命令所在目录下 创建一个dist文件夹 dist文件夹下会有一个main.js npx webpack
在当前目录下创建index.js
对打包后的js进行引用即可
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <script src="dist/main.js"></script> </body> </html>
浏览器访问可以看到正常输出,说明互相引用是可以的。
具体原理还得看main.js
webpack打包出来的文件
总结
到此这篇关于前端JavaScript模块化解析之ESModule用法示例的文章就介绍到这了,更多相关JS模块化ESModule内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!