关于模块导出

229 阅读3分钟

背景

在使用ts+node过程中,发现一个现象。搭建过程使用module.exports导出会引发命名重复的ts报错。但是使用export default 则不会。

那么我们就来整理一波模块导出相关的知识。

模块,common.js

Node.js的模块是基于common.js实现的。

module.exports

示例

文件结构:

/index:

console.log('模块index')
const A = require('./moduleA')
const B = require('./moduleB')
const index = "index"
console.log('A', A)
console.log(module)

/moduleA.js:

console.log('模块A')
function  A () {
    console.log('A')
}
module.exports = A

/moduleB.js:

console.log('模块B')
function  B () {
    console.log('B')
}
module.exports = B

执行index文件的打印结果:

Module {
  id: '.',
  path: '/Users/zyf/Desktop/test/module',
  exports: {},
  parent: null,
  filename: '/Users/zyf/Desktop/test/module/index.js',
  loaded: false,
  children: [
    Module {
      id: '/Users/zyf/Desktop/test/module/moduleA.js',
      path: '/Users/zyf/Desktop/test/module',
      exports: [Function: A],
      parent: [Circular],
      filename: '/Users/zyf/Desktop/test/module/moduleA.js',
      loaded: true,
      children: [],
      paths: [Array]
    },
    Module {
      id: '/Users/zyf/Desktop/test/module/moduleB.js',
      path: '/Users/zyf/Desktop/test/module',
      exports: [Function: B],
      parent: [Circular],
      filename: '/Users/zyf/Desktop/test/module/moduleB.js',
      loaded: true,
      children: [],
      paths: [Array]
    }
  ],
  paths: [
    '/Users/zyf/Desktop/test/module/node_modules',
    '/Users/zyf/Desktop/test/node_modules',
    '/Users/zyf/Desktop/node_modules',
    '/Users/zyf/node_modules',
    '/Users/node_modules',
    '/node_modules'
  ]
}

可以这样理解,node项目中,每个文件就是一个模块(module)

我们使用module.exports = variable, 实际上,是将本模块中的方法或者变量挂载在当前module的exports属性上。

使用const A = require('./moduleA.js'),引用的就是moduleA中exports属性的内容

module.exports 在同一个文件中只能导出一次,最后一次导出才有效。

多项导出采用这样的方式:

module.exports = {
    A,
    copyA
}
// 或者
module.exports.A = A
module.exports.copyA = copyA

exports

我将moduleA.js文件做修改

console.log('模块A')
function  A () {
    console.log('A')
}
function copyA () {
    console.log('copyA')
}
exports = {A}

打印结果

再改:

console.log('模块A')
function  A () {
    console.log('A')
}
function copyA () {
    console.log('copyA')
}
exports.A = A

打印结果:

表象:

  • 直接使用exports = 变量,会使模块的导出为空。

  • 使用exports.A = A导出,才能导出对应的模块,且模块内容为object.

这样,我们就可以理解了。exports 其实是对module.exports 的引用。

相当于

let exports = module.exports

直接使用等号,相当于变更了引用。所以导出的内容为空。

ES6模块导出

使用export ,import

这里export,import 是关键字,而不是变量或者方法。

所以es6的导出和引入就可以理解为单纯的导出和导入。

Export 指令

// 导出多个,造一个对象,对象中包含A,B
export {
    A,
    B            
}

// 导出单个, 需要使用export default
// 报错
export A
// 正确
export default A

Import 指令

//导入默认
import A from './moduleA.js'

// 导入多个,可实现按需加载
import {A, B, C} from './module.js'
// 多个整体导入
import * as All from './module.js'

Export 与export default 区别

  • 在一个文件或者模块中,export和import可以有多个,但是export default却仅有一个。

  • 通过export方式导出,再导入时需要加{},按需加载。但是export default不需要。

  • 输出单个模块时使用export default,多个模块时使用export。

  • 不要同时使用。

结论

common.js模式的导入导出,是以对象的形式进行的。所有的模块还是在同一个作用域中。

ES6的模块导入导出可以将不同的模块彼此独立。

在使用Typescript时,建议采用es6的导出导出规则,来避免同名变量报错的问题。

参考资料

ES6: module的语法