Node.js 和浏览器的 JavaScript 最大的不同就在于 Node.js 是模块化的。
- Node.js只是一个平台,不是新的语言。
什么是模块化?
代码具有模块结构,整个应用可以自顶向下划分为若干个模块,每个模块彼此独立,代码不会相互影响。模块化的目的是使代码可以更好地复用,从而支持更大规模的应用开发。
为什么使用js定义模块报错了?
Node.js 目前默认用
CommonJS
规范定义 .js 文件的模块,用ES Modules
定义 .mjs 文件的模块。如果我们直接将index.mjs
文件改成index.js
,然后运行node index.js
,则会报错解决方案?
如果要用
ES Modules
定义 .js 文件的模块,可以在 Node.js 的配置文件package.json
中设置参数type: module
,如下:
{ "type": "module" }
模块定义与引用
1. ES Modules模式
// model.js
const log = (message) => {
console.log(message)
};
const err = (message) => {
console.err(message)
};
const USERANME = '张三';
export { log };
// index.js
import { log, err as errorMessage, USERANME } from './model.js'
log(USERANME);
errorMessage('我是错误文案')
ES Modules支持default
模式,可以用任意名称表示
// model.js
// 先定义再批量导出api
const default log = (message) => {
console.log(message)
};
export log;
// 最后统一导出api
const default log = (message) => {
console.log(message)
};
export default log;
// index.js
import logFn from './model.js'
logFn('hello world');
批量导入
// model.js
const USERANME = '张三';
const default log = (message) => {
console.log(message)
};
const err = (message) => {
console.err(message)
};
export log;
export { USERANME, err };
// index.js
import * as funcs from './model.js'
funcs.err(funcs.USERANME);
funcs.default(funcs.USERANME)
这里需要注意一下,default
格式的方法,是通过.default
进行访问的,不再是model.js里面定义的方法的名字。
2. CommonJS
// model.js
const log = (message) => {
console.log(message)
};
module.exports log;
// index.js
const logFun = require('./model.js');
logFun('hello world')
实际上CommonJS
和ES Modules
类似,和ES Modules
不同的地方是,CommonJS
采用module.exports/require
而ES Modules
则采用export/import
。
同样,CommonJS也支持同时导出多个方法及参数,因为CommonJS导出的是真正的对象,所以可以起别名
// model.js
const USERANME = '张三';
const log = (message) => {
console.log(message)
};
const err = (message) => {
console.err(message)
};
module.exports = { USERANME, log, err as errMessage }
// index.js
const { USERANME, log, errMessage } = require('./model.js')
log(USERANME);
errMessage(USERANME);
下面这种情况,会重写导出的默认空间
// model.js
defaults.USERANME = '张三';
defaults.log = (message) => {
console.log(message)
};
defaults.err = (message) => {
console.err(message)
};
const overWrite = () => {
console.log('我重写了默认导出空间')
}
module.default = { overWrite } // 在这里重写了导出默认空间
const { overWrite } = require('./model.js')
overWrite()
需要注意的是,两种写法不能混用,因为:
const log = (message) => {
console.log(message)
};
const err = (message) => {
console.err(message)
};
module.exports = { log, err }
等效于
const log = (message) => {
console.log(message)
};
const err = (message) => {
console.err(message)
};
// const value = { log, err };
// export default value;
export default { log, err };
ES Modules与CommonJS的主要区别
-
导出方式及导出重命名方式不同
- ES Modules导出时候要写作
export { log as logMessage }
; - CommonJS导出时候要写作
module.exports = { logMessage: log }
- ES Modules导出时候要写作
-
引用方式不同
- ES Modules导出时候要写作
import { log } from './model.js'
,文件后缀不可省; - CommonJS导出时候要写作
const { log } = require('./model.js')
,文件后缀可以省;
- ES Modules导出时候要写作
-
引用位置可以不同
-
ES Modules使用
import
方式引用时候,只能写在文件最外层,不能再局部引用; -
CommonJS使用
require
方式引用时候,可以写在最外层,也可以写在局部作用const { log } = require('./model') if(true) { const { err } = require('./model') }
-
-
引用路径限制不同
-
ES Modules使用
import
方式引用时候,路径必须是固定的; -
CommonJS使用
require
方式引用时候,路径可以是有变量的;const path = 'model.js' const { log } = require(`./${path}`) log('hello world')
-
虽然ES Modules不允许再语句块中设置动态参数,但是它提供了一个
将import作为异步函数
的机制,所以可以这样引用:(async ()=>{ await import { log } from './model.js' log('hello world') })()
一般我们引用都是写在最外面,除非在项目中,不同平台环境下,引用的不是一个模块,这种时候就必须要动态加载了(如果加载所有模块,会消耗性能)。
-