module.exports/exports/require、export/import/export default的区别

191 阅读1分钟

‪Module Cheatsheet 这篇文章里面说的很清楚了。

图片

// Name Export | Name Import
export const name = 'value'
import { name } from '...'

// Default Export | Default Import
export default 'value'
import anyName from '...'

// Rename Export | NameImport
export { name as newName }
import { newName } from '...'

// Name + Default | Import All
export const name = 'value'
export default 'value'
import * as anyName from '...'

// Export List + Rename | Import List + Rename
export {
  name1,
  name2 as newName2
}
import {
  name1 as newName1,
  newName2
} from '...'

module.exports/exports/require

如果使用 es6,不建议使用该方式

module.exports/exports

module.exports = { xxx }
module.exports.xxx = xxxxxx
exports.xxx = xxxxxx

其实 exports 就相当于

const exports = module.exports

所以是没法使用

exports = { xxx }

因为你没法办法改变一个 const 修饰指针的对象,修改对象的属性还是可以的。

require

module.exportsexports 配对使用

A 模块导出
module.exports.xxx = () => {}

B 模块使用
const A = required('A')
A.xxx()

export/import

es6 支持的语法,推荐使用

export { xxx, xx, x }
import { xxx, xx, x } from 'xxx'

export default

只有一个默认的导出模块

export default { xxx }
import xxx from 'xxx'

这里就可以看出来了,由于只有一个模块,所以就可以不使用元组解包了。

补充

全局污染

由于早期 js 中没有模块的概念,所以变量很容易造成全局污染。

怎么解决?

IIFE(立即调用函数表达式)

(function(window) {
    let msg = "msg"
    toast() {
        msg = "msg-toast"
        console.log(msg)
    }
    window.module = { toast }
})(window)

其实本质就是把用 IIFE 把作用域限定在闭包内了,也就不存在全局污染的问题了。

模块间引用?

function(window, $) {
    foo() {
        $('body').css('background', 'red')
    }
    window.module = { foo }
}(window, jQuery)

也是一个道理,把对应的模块传进需要引入的模块。

commonJS/AMD

由上述的原理,就可以形成一套模块的规范了。上面的 module.exports/exports/require 就是这个。

commonJS 同步加载,AMD 异步加载。

如何选择

如果支持 es6,就选 export/import/export default,否则,除了 commonJS 等等,你也没得挑了~