美文网首页
模块化规范:ES Modules

模块化规范:ES Modules

作者: JerrySi | 来源:发表于2021-12-29 23:57 被阅读0次

一、ES Module基本特性

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>ES Module - 模块的特性</title>
</head>
<body>
  <!-- 通过给 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 模块的 -->
  <!-- 不支持CORS-->
  <!-- <script type="module" src="https://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script> -->
  <!-- 支持CORS-->
  <script type="module" src="https://unpkg.com/jquery@3.4.1/dist/jquery.min.js"></script>

  <!-- 4. ESM 的 script 标签会延迟执行脚本 = defer属性 -->
  <script type="module" src="demo.js"></script>
  <p>需要显示的内容</p>
</body>
</html>

二、导出

  1. 单独导出
export var name = 'foo module'
export function hello () {
  console.log('hello')
}
export class Person {}

import { name } from './module.js'
import { hello } from './module.js'
import { Person } from './module.js'
  1. 合并导出
export { name, hello, Person }

import { name, hello, Person } from './module.js'
  1. 别名
// 以default方式导出, import的时候必须使用别名
export {
  name as default,
  hello as fooHello,
  Person
}

// default使用的话必须设置别名,foolHello和Person可以不用设置
// 别名可以叫任意名字
// import { default as name, fooHello as hello, Person } from './module.js'
import name, { fooHello as hello, Person } from './module.js'

三、导出注意事项

1. 对象后面的花括号和export后的花括号是不同的概念:一个是【对象】,一个是导出【引用】。

比如,这两个花括号是不一样的:

var obj = { name, age } // 这个花括号是个对象
export { name, age } // 这个花括号是个引用

错误:

export name // 错误的导出用法
export 'foo' // 同样错误的导出用法

可以这样导出变量名

export default name 
2. 导出导入的是引用的内存地址

导出: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)

// 导入成员并不是复制一个副本,
// 而是直接导入模块成员的引用地址,
// 也就是说 import 得到的变量与 export 导入的变量在内存中是同一块空间。
// 一旦模块中成员修改了,这里也会同时修改,
setTimeout(function () {
  console.log(name, age)
}, 1500)

// 输出 jack 18
3. 导入的变量只读不能修改
import { name, age } from './module.js'
name=1 //Uncaught TypeError: Assignment to constant variable.=

四、导入用法

// 一、文件导入的方法
import { name } from './module' // 1.不能省略.js,这点跟ComminJs是不一样的
import { name } from './module.js'
console.log(name)

import { lowercase } from './utils' // 2.不能只导入目录就可以找到index.js,这跟CommonJS是不一样的
import { lowercase } from './utils/index.js' 
console.log(lowercase('HHH'))

import { name } from 'module.js' //3.不能以字母开头,因为ES Module就以为在加载第三方模块,而不是本地路径模块了,这点和CommonJS是相同的
import { name } from './module.js'
import { name } from '/04-import/module.js' // 4.可以用绝对路线省略/前的• → 根目录就是当前index.html目录 
import { name } from 'http://localhost:3000/04-import/module.js' 
console.log(name)

// 二、仅仅导入模块执行,而不需要使用对象
import {} from './module.js' 
import './module.js'

// 三、把模块下所有的export属性都导出来,可以用 * 
import * as mod from './module.js' // 
console.log(mod)

// 四、2个不能 → 解决方案
var modulePath = './module.js' //1.不能将导入模块赋值给一个变量
import { name } from modulePath // 这才是正确导入写法
console.log(name)

// 2.不能嵌套在一个if、while语句中,只能在最顶层就导出模块
if (true) {
  import { name } from './module.js' 
}

// 3.解决方案:全局动态的导入方案,通过then拿到这个模块。
import('./module.js').then(function (module) { 
  console.log(module)
})

// 五、提取默认成员
// 1.复杂:默认成员导出方式
import { name, age, default as title } from './module.js' 
// 2.简写:逗号左边用来提取默认成员,逗号右边用来提取具名成员。
import abc, { name, age } from './module.js'
console.log(name, age, abc)

五、多文件导入用法

// 在文件夹中新建一个index.js文件, 然后把文件夹中需要导出的模块都列出来
export { default as Button } from './button.js'
export { Avatar } from './avatar.js'

// 在需要倒入的文件中一次导入
import { Button, Avatar } from './components/index.js'

六、polyfill(正式环境不使用)

<!-- https://github.com/ModuleLoader/browser-es-module-loader -->
  <!-- browser-es-module-loader导入不识别的文件给babel去解析-->
  <!-- nomodule 只有在不识别的时候才引入-->
  <script nomodule src="https://unpkg.com/promise-polyfill@8.1.3/dist/polyfill.min.js"></script>
  <script nomodule src="https://unpkg.com/browser-es-module-loader@0.4.1/dist/babel-browser-build.js"></script>
  <script nomodule src="https://unpkg.com/browser-es-module-loader@0.4.1/dist/browser-es-module-loader.js"></script>  

七、Node中使用ES Modules

从node 8.5后就支持Node环境中是ES Modules。具体做法就是把js的后缀名改成mjs

// 也可以直接提取模块内的成员,内置模块兼容了 ESM 的提取成员方式
import { writeFileSync } from 'fs'
writeFileSync('./bar.txt', 'es module working')

// 对于第三方的 NPM 模块也可以通过 esm 加载
// import _ from 'lodash'
// _.camelCase('ES Module')

// // 不支持,因为第三方模块都是导出默认成员
// // import { camelCase } from 'lodash'
// // console.log(camelCase('ES Module'))

Node v12 之后的版本,可以通过 package.json 中添加 type 字段为 module,
将默认模块系统修改为 ES Module,此时就不需要修改文件扩展名为 .mjs 了。
但是如果你想使用CommonJS,那么js后缀名要修改位cjs。

八、ES Modules 和 CommonJS 交互

// CommonJS 模块始终只会导出一个默认成员
// module.exports = {
//   foo: 'commonjs exports value'
// }
 exports.foo = 'commonjs exports value'

// ES Module 中可以导入 CommonJS 模块
 import mod from './commonjs.js'
 console.log(mod)
// 不能直接提取成员,注意 import 不是解构导出对象
// import { foo } from './commonjs.js'
// ES Module
export const foo = 'es module export value'

// 不能在 CommonJS 模块中通过 require 载入 ES Module
// const mod = require('./es-module.mjs')
image.png

九、ES Modules 和 CommonJS 不同点

CommonJS中可以有下面5个对象:

// 加载模块函数
console.log(require)
// 模块对象
console.log(module)
// 导出对象别名
console.log(exports)
// 当前文件的绝对路径
console.log(__filename)
// 当前文件所在目录
console.log(__dirname)

但是对应ES Modules中没有了, 可以按照下面方式替代:

// require, module, exports 自然是通过 import 和 export 代替
// __filename 和 __dirname 通过 import 对象的 meta 属性获取
// const currentUrl = import.meta.url
// console.log(currentUrl)

// 通过 url 模块的 fileURLToPath 方法转换为路径
import { fileURLToPath } from 'url'
import { dirname } from 'path'
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)

相关文章

  • js模块化规范

    一、js模块化1、模块化规范: script CommonJS AMD CMD ES6 modules 2、scr...

  • 模块化规范:ES Modules

    一、ES Module基本特性 二、导出 单独导出 合并导出 别名 三、导出注意事项 1. 对象后面的花括号和ex...

  • js模块化

    首先梳理一下模块化的发展情况~ 无模块化-->CommonJS规范-->AMD规范-->CMD规范-->ES6模块...

  • JavaScript的四种模块化规范

    CommonJS规范 由于ES5没有模块化规范,所以产生了这三种规范。在ES6中又新增了一种公用模块化的方法。特点...

  • js模块化

    js的模块化大致分为4种规范 amd cmd commonjs 和es6模块化 1.amd规范 amd规范又叫异步...

  • 前端H5 SPA选型

    前台规范 ES6语法ES6前端代码规范 前端模块化管理 webpack 构建工具 vue-loader 前端CSS...

  • 前端模块化:ES6,CommonJS

    前端模块化 共有四种规范 ES6 Module CommonJS AMD CMD ES6 Module ES6模块...

  • JS模块化

    模块化规范:CommonJS,AMD,CMD,UMD,ES6 Module CommonJS CommonJS是服...

  • ES6学习(14)模块化

    ES6 之前的模块化规范有:CommonJS => NodeJS、Browserify;AMD => requir...

  • 2019年前端面试都聊啥?提前来看看

    JavaScript ES2015 规范出现后,一切都大变样啦。 该规范很大——随着对modules(模块)原生支...

网友评论

      本文标题:模块化规范:ES Modules

      本文链接:https://www.haomeiwen.com/subject/pijbqrtx.html