关于 JS 的模块化
ESM 具有 延迟解析 和 严格模式 的特点,是通过跨域(CORS)的方式请求外部 JS 模块的(所以需要服务端支持跨域,普通 script 标签不存在跨域)。
模块的作用域:每个 ESM 模块都是单独的私有作用域。
js
<script>
let name = 'hello'
</script>
<script>
console.log(name) // hello
</script>
// ------------------------------ //
<script type="module">
let name = 'hello'
</script>
<script>
console.log(name) // site is not defined
</script>
<script type="module">
console.log(name) // site is not defined
</script>
模块预解析必要性:同一个模块被导入多次,只需执行一次。
模块的导出与导入:
js
// 具名导入导出
// util.js
export let name = 'hello'
export function getName() {
return name
}
export class User {
static render() {
return 'render user'
}
}
// 或者这样写也可以
let name = 'hello'
function getName() {
return name
}
class User {
static render() {
return 'render user'
}
}
export { name, getName, User }
//index.js
import { name, getName, User } from './util.js' // 批量导入
console.log(name)
console.log(getName())
console.log(User.render())
import * as Util from './util.js' // 全量导入
console.log(Util.name)
console.log(Util.getName())
console.log(Util.User.render())
// 别名导出导入
// util.js
export { name, getName as readName, User }
// index.js
import { name as n, readName } from './util.js'
let name = 'world'
console.log(n)
console.log(readName())
default 默认导出
js
//util.js
export default class User {
static render() {
return 'render user'
}
}
// 或者下面写法
class User {
static render() {
return 'render user'
}
}
export { User as default }
// index.js
import User from './util.js'
import u from './util.js' // 默认导入可以随便起名
// 或者下面写法
import { default as u } from './util.js'
混合导入导出
js
//util.js
export let name = 'hello'
export default class User {
static render() {
return 'render user'
}
}
// 或者下面写法
let name = 'hello'
class User {
static render() {
return 'render user'
}
}
export { User as default, name }
// index.js
import User, { name } from './util.js'
console.log(User.render(), name)
// 这样写
import * as Util from './util.js'
console.log(Util) // {default: , name: ,}
console.log(Util.default.render())
console.log(Util.default.name)
模块合并导出
js
// util.1js
export let url = 'youtube.com'
// util.2.js
export let name = 'hello'
export default class User {
static render() {
return 'render user'
}
}
// util.js
import { url } from './util.1.js'
import User, { name } from './util.1.js'
// 如何合在一起?看下面
export { url, name, User }
// index.js
import { url, name, User } from './util.js'
// 但是如果 util 文件导入 同名字段怎么办?看下面
// util.js
import * as util1 from './util.1.js'
import * as util2 from './util.1.js'
export { util1, util2 }
// index.js
import * as Util from './util.js'
console.log(Util) // {util1, util2}
console.log(Util.util1.url)
console.log(Util.util2.name)
console.log(Util.util2.default.render())
按需加载模块
js
import('./util.js') //返回值是 promise 对象
import('./util.js').then((module => {
console.log(module)
}))
// 放在逻辑判断里面也没有问题
if(name === 'hello') {
import('./util.js').then(({name, url} => {
console.log(name, url)
}))
}