背景
在使用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的语法