CommonJS
CommonJS是一个规范,最初提出来是在浏览器以外的地方使用,并且当时被命名为ServerJS,后来体现它的广泛性,修改为CommonJS(简称CJS)
- Node是CommonJS在服务器端一个具有代表性的实现
- Browserify是CommonJS在浏览器中的一种实现
- webpack打包工具具备对CommonJS的支持和转换
CommonJS的基本使用other.js```javascript const dataList = [1, 3, 6, 3, 2]
function sum(a, b) { return a + b }
module.exports = { dataList, sum }
`main.js`
```javascript
const other = require('./other.js')
console.log(other.dataList); // [ 1, 3, 6, 3, 2 ]
console.log(other.sum(10, 20)); // 30
内部原理: 在other.js中,有一个变量
module,可以给module.exports赋值一个对象。 当外部文件通过require()调用时,会获取module.exports。main.js中的other和other.js中的module.exports是同一个对象。
通过exports导出
这种方式不建议使用other.js
const dataList = [1, 3, 6, 3, 2]
function sum(a, b) {
return a + b
}
exports.dataList = dataList
exports.sum = sum
:::danger
注意:不能用exports = { ... }
:::
内部(源码)原理 module.exports = {} exports = module.exports 所以使用
exports = { ... }不会影响module.exports
require()
require是一个函数,可以帮助我们引入一个文件(模块)中导出的对象。
基本格式:require(X)
情况一:X为核心模块
// fs和path为node的核心模块
const fs = require('fs')
const path = require('path')
情况二:X以’./‘、’../‘、’/‘开头
- 把X当作是一个文件- 如果X有后缀名,按后缀名的格式查找对应的文件
- 如果X没有后缀名- 查找文件X
- 查找X.js文件
- 查找X.json文件
- 查找X.node文件
 
- 查找文件
 
- 把X当作是一个目录- 查找目录下的index文件- 查找X/index.js文件
- 查找X/index.json文件
- 查找X/index.node文件
 
- 查找
 
- 查找目录下的index文件
- 如果没有找到,就报错not find
情况三:一个不是核心模块的普通字符串会在当前目录下的node_modules下查找,没有会查找上一级node_modules,直到查找到根目录  模块加载细节
- 模块在被第一次引入时,模块中的js代码会被运行一次
- 模块被多次引入时,会缓存,最终只加载(运行)一次 :::info 为什么只能被载一次? 
 因为模块对象module都有哦一个属性loaded。为true时表示已经被加载过了。 :::
- 循环引入采用深度优先遍历算法加载  执行顺序为:main-A-B-C-G-D-E-F 执行顺序为:main-A-B-C-G-D-E-F
ES Module
 JavaScript没有模块化一直是它的痛点,所以才会产生我们前面学习的社区规范:CommonJS、AMD、CMD等。
 ES Module和CommonJS的模块化有一些区别:
- ES Module采用了import和export来导入导出。
- 采用编译器的静态分析和动态引入的方式。export:负责将模块内的内容导出 import:负责将其他模块的内容导入 
ES Module的基本使用
other.js
// syntax: export <declaration statement>
export const msg = "hello"
export function foo() {
  console.log("foo")
}
main.js
// 导入外部文件的内容
import {msg, foo} from "./other.js";
console.log(msg)
foo()
index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
  <!-- 需要加上type="module" -->
  <script src="./main.js" type="module"></script>
</body>
</html>
错误案例分析
- 缺少type="module"的情况:

- 直接在本地打开文件(用浏览器运行文件,而不是服务)

这个在MDN上面有给出解释: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Modules 你需要注意本地测试 — 如果你通过本地加载Html 文件 (比如一个 file:// 路径的文件), 你将会遇到 CORS 错误,因为 Javascript 模块安全性需要。 你需要通过一个服务器来测试。
- VSCode,VSCode中有一个插件:
Live Server- WebStorm:以浏览器打开时会自动启动一个服务器
ES Module 导出
export的多种用法
- 在语句声明的前面直接加上export关键字export const msg = "hello"。
- 将所有需要导出的标识符,放到export后面的 { }中。\ :::danger 注意:这里的 - { }里面不是ES6的对象字面量的增强写法,- { }也不是表示一个对象的;
 所以: export {name: name},是错误的写法;
 :::
- 导出时给标识符起一个别名 。 - const name = "foo" export { name as newName }- ES Module 导入- import的多种用法
- 导入所需的 - import {b} from 'a'
- 通过 *导入一个模块中所有导出的内容import * as b from 'a'
- 导出时可以起别名import { b as c } from 'a'ES Module 导入和导出的结合使用在开发和封装一个库时, 通常我们希望将暴露的所有接口放到一个文件中;这样方便指定统一的接口规范,也方便阅读; 这个时候,我们就可以使用export和import结合使用。 ```javascript // 将模块a的内容全部导出 export * from ‘a’
// 将模块b的c导出 export { c } from ‘b’
// 将模块d中的e重命名为f并导出 export { e as f} from ‘d’
<a name="xp48M"></a>
### ES Module default关键字
 默认导出export时可以不需要指定名字;在导入时不需要使用 {},并且可以自己来指定名字; 它也方便我们和现有的CommonJS等规范相互操作;
<a name="dg9JX"></a>
#### 默认导出方式一:export default
`other.js`
```javascript
export const msg = "hello"
export function foo() {
  console.log("foo")
}
function bar() {
  console.log("bar")
}
// 默认导出
export default bar
main.js
import {msg, foo} from "./other.js";
// 默认导出,可以自己起名
import baz from './other.js'
console.log(msg)
foo()
baz()
结果: :::warning
注意:在一个模块中,只能有一个默认导出(default export);
:::warning
注意:在一个模块中,只能有一个默认导出(default export);
:::
默认导出方式二:export { a as default }
const msg = "hello"
function foo() {
  console.log("foo")
}
function bar() {
  console.log("bar")
}
// 效果同方式一
export {
    msg,
  foo,
  bar as default
}
import()函数
通过import加载一个模块,是不可以在其放到逻辑代码中的
为什么会出现这个情况呢?
- import是同步加载
- 这是因为ES Module在被JS引擎解析时,就必须知道它的依赖关系;
- 由于这个时候js代码没有任何的运行,所以无法在进行类似于if判断中根据代码的执行情况;
:::info
import()函数是异步加载,返回Promise
:::
const flag = true
if (flag) {
  import('./a.js').then(res => {
    // res为Module对象,可以通过res.property获取模块内容
    console.log(res)
  })
} else {
  import('./b.js').then(res => {
    console.log(res)
  })
}
import meta
import.meta是ES11中新增的特性。 一个给JavaScript模块暴露特定上下文的元数据属性的对象。它包含了这个模块的信息,比如说这个模块的URL;  
 
                         
                                

