模块化ESModules

327 阅读2分钟

ESModules基本特性

  1. ESM自动采用严格模式,忽略'use strict'
  2. 每个ES Module 都是运行在单独的私有作用域中
  3. ESM是通过CORS的方式请求外部JS模块的
  4. ESM的script标签会延迟执行脚本
  <!-- 通过给 script 添加 type = module 的属性,就可以以 ES Module 的标准执行其中的 JS 代码了 -->
  <script type="module">
    console.log('this is es module')
  </script>

  <!-- 1. ESM 自动采用严格模式,忽略 'use strict' -->
  <script type="module">
    console.log(this)
  </script>

  <!-- 2. 每个 ES Module 都是运行在单独的私有作用域中 -->
  <script type="module">
    var foo = 100
    console.log(foo)
  </script>
  <script type="module">
    console.log(foo)
  </script>

  <!-- 3. ESM 是通过 CORS 的方式请求外部 JS 模块的 -->
  <!-- <script type="module" src="https://unpkg.com/jquery@3.4.1/dist/jquery.min.js"></script> -->

  <!-- 4. ESM 的 script 标签会延迟执行脚本 -->
  <!-- 相当于用了defer -->
  <script defer src="demo.js"></script>
  <p>需要显示的内容</p>

ESModules导入导出

// 导出变量
export var name = 'foo module'
// 导出函数
export function hello () {
  console.log('hello')
}
// 导出类
export class Person {}
var name = 'foo module'
function hello () {
  console.log('hello')
}
class Person {}
// 集中导出更为常用
export { name, hello, Person }
// 导入
import { name, hello, Person } from './module.js'
*****************
// 重命名导出
export {
   hello as fooHello, 
   name as default // 这种导出导入的时候必须重命名
 }
import { default as fooName } from './module.js'
*****************
// 默认导出
export default name
// 导入 的时候名字自己起
import fooName from './module.js'

导入导出注意事项

// 这里的 `{ name, hello }` 不是一个对象字面量,
// 它只是语法上的规则而已
export { name, age }
// ES Module 中 { } 是固定语法,就是直接提取模块导出成员, 并不是对象结构
import { name, age } from './module.js'

*********************

// 这个时候导出的就是一个对象
export default { name, age }

*********************

// 通过下面这个例子可以发现是将值的引用关系给到了外部,并不是拷贝到了外部
// module.js
var name = 'jack'
var age = 18
export { name, age }
setTimeout(function () {
  name = 'ben'
}, 1000)

// app.js
import { name, age } from './module.js'
console.log(name, age) // jack 18
// name = 'tom' // 会报错 不能修改
setTimeout(function () {
  console.log(name, age) // ben 18
}, 1500)

导入的用法

// import { name } from './module'  // 不能省略路径拓展名
import { name } from './module.js'

// import { lowercase } from './utils' // 不能省略index.js
import { lowercase } from './utils/index.js'
// 以上两点在后期使用打包工具的时候可以省略

// import { name } from 'module.js' // 不能省略./
import { name } from './module.js'

import { name } from '/04-import/module.js' // 可以使用绝对路径
import { name } from 'http://localhost:3000/04-import/module.js' // 可以使用完整的URL

// 只是执行某个模块并不需要提取成员可以这样
import {} from './module.js' 
import './module.js'

// 提起全部成员放到一个对象中,每个成员将作为这个对象的属性
import * as mod from './module.js'

// 动态加载模块
import('./module.js').then(function (module) {
  console.log(module)
})

*************************
// module.js
var name = 'jack'
var age = 18
export { name, age }
console.log('module action')
export default 'default export'

// app.js
// 同时导入默认成员和命名成员 默认成员名字可以自己起
import { name, age, default as title } from './module.js'
import abc, { name, age } from './module.js'
console.log(name, age, abc)

导出导入成员

// 可以将导入的结果直接作为当前模块的导出成员
export { foo, bar } from './module.js'

// 利用这个这个特性可以把某个目录下散落的模块通过这种方式组织在一起导出,方便外部使用
// 例如components文件夹下有avatar.js和button.js,我们此时再新建一个index.js
*************index.js********************
import { Button } from './button.js'
import { Avatar } from './avatar.js'
export { Button, Avatar }

*************app.js********************
import { Button, Avatar } from './components/index.js'

image.png

浏览器环境Polyfill