模块化目的

  • 解决命名冲突
  • 提供复用性
  • 提高代码可维护性

ES Module

  • export

    • 默认导出export default Person

    • 按需导出export { age, name, sex }(推荐)

    • // 导出变量
      export const name = "蛙人"
      export const age = 24
      
      // 导出函数也可以
      export function fn() {}
      export const test = () => {}
      
      
// 如果有多个的话
const name = "skinner"
const age = 33
export { name, age }
```
  • 混合导出与导入

    可以使用exportexport default同时使用并且互不影响,只需要在导入时地方注意,如果文件里有混合导入,则必须先导入默认导出的,在导入单个导入的值。

    //混合导出
    export const name = "skinner"
    export const age = 33
    
    export default {
        fn() {},
        msg: "hello skinner"
    }
    
    
    
//混合导入,则该文件内用到混合导入,import语句必须先是默认导出,后面再是单个导出,顺序一定要正确否则报错。
// index,js
export const name = "skinner"
export const age = 24
export default {
    msg: "skinner"
}

import msg, { name, age } from './index.js'
console.log(msg)
```
    • import
  • 默认导入:import Person from "person"

  • 按需导入import { age, name, sex } from "person"

  • 导入值的变化

    export导出的值是值的引用,并且内部有映射关系,这是export关键字的作用。而且导入的值,不能进行修改也就是只读状态。

    // index.js
    export let num = 0;
    export function add() {
        ++ num
    }
    
    import { num, add } from "./index.js"
    console.log(num) // 0
    add()
    console.log(num) // 1
    num = 10 // 抛出错误
  • Es Module是静态

    if (true) {
        import xxx from 'XXX' // 报错
    }

CommonJS

  • CommonJS:用于服务器(动态化依赖)
  • AMD:用于浏览器(动态化依赖)
  • CMD:用于浏览器(动态化依赖)
  • ES6 module

CommonJS

注意:浏览器不识别CommonJS语法,因此需要采用browser 打包处理

语法:

  • module.exports = value | exports.xxx = value

    //a.js
    
    //方式1:
    //注意!!:向外暴露的是exports对象,原始exports是{}
    module.exports = {
        a: 1
    }
    
    //方式2
    exports.a = 1
    // b.js
    var module = require('./a.js')
    module.a // -> log 1

    先说b.js中的require,其实就是包装了一层立即执行函数,避免污染全局变量

    再说a.js,首先我们需要知道module是怎么实现的,如下。module中有一个特定id,还有一个exports属性

    // module 基本实现
    var module = {
      id: 'xxxx', // 我总得知道怎么去找到他吧
      exports: {} // exports 就是个空对象
    }

    为什么CommonJS有两个语法,原因如下:

    // 这个是为什么 exports 和 module.exports 用法相似的原因
    var exports = module.exports 

    注意:
    虽然 exports 和 module.exports 用法相似,但是不能对 exports 直接赋值。因为 var exports = module.exports 这句代码表明了 exports 和 module.exports 享有相同地址,通过改变对象的属性值会对两者都起效,但是如果直接对 exports 赋值就会导致两者不再指向同一个内存地址,修改并不会对 module.exports 起效。

    再说require执行的是什么函数

    //require执行load函数
    var load = function (module) {
        // 导出的东西
        var a = 1
        module.exports = a
        return module.exports
    };
    // 然后当我 require 的时候去找到独特的
    // id,然后将要使用的东西用立即执行函数包装下
  • 特点

    • 不支持重复导入

      let data = require("./index.js")
      let data = require("./index.js") // 不会在执行了
    • 动态导入

      CommonJs支持动态导入,什么意思呢,就是可以在语句中,使用require语法,来看如下案例。

      let lists = ["./index.js", "./config.js"]
      lists.forEach((url) => require(url)) // 动态导入
      
      if (lists.length) {
          require(lists[0]) // 动态导入
      }
    • 导入值是拷贝值

      CommonJs导入的值是拷贝的,所以可以修改拷贝值,但这会引起变量污染,一不小心就重名。

      // index.js
      let num = 0;
      module.exports = {
          num,
          add() {
             ++ num 
          }
      }
      
      let { num, add } = require("./index.js")
      console.log(num) // 0
      add()
      console.log(num) // 0
      num = 10

      上面example中,可以看到exports导出的值是值的拷贝,更改完++ num值没有发生变化,并且导入的num的值我们也可以进行修改

CommonJs和Es Module的区别

CommonJs

  • CommonJs可以动态加载语句,运行时
  • CommonJs混合导出,还是一种语法
  • CommonJs导出值是拷贝,可以修改导出的值,这在代码出错时,不好排查引起变量污染

Es Module

  • Es Module是静态的,不可以动态加载语句,编译时
  • Es Module混合导出,单个导出,默认导出,完全互不影响
  • Es Module导出是引用值之前都存在映射关系,并且值都是可读的,不能修改