「这是我参与2022首次更文挑战的第15天,活动详情查看:2022首次更文挑战」
commonJS
定义:
是一种代码模块化的规范,nodeJS就采用commonJS规范
特点:
- 每一个文件是一个模块,每一个模块,都有一个module对象,下面有几个属性
module.id模块的识别符,通常是带有绝对路径的模块文件名。module.filename模块的文件名,带有绝对路径。module.loaded返回一个布尔值,表示模块是否已经完成加载。module.parent返回一个对象,表示调用该模块的模块。module.children返回一个数组,表示该模块要用到的其他模块。module.exports表示模块对外输出的值。
- 我们要导出的内容,就挂载在module.exports属性上
- 页面内有一个exports属性,它指向module.exports,所以也可以直接把要导出的内容挂载到exports属性上,但是不要修改exports的引用,否则,它就不指向module.exports了,你再给它挂载属性就不生效了。
- CommonJS是同步加载的。
- require命令,用于加载指定模块的module.exports对象
- 路径带"./"或者"/",则去本地指定路径找,否则去node_modules里找
- 作位npm包的话,最好在package.json指定入口路径,如
"main":"/xxxx/index.js",这样require的时候就直接去加载这个路径对应的文件了,如果没有main,那么会去加载根目录下的index.js - require实际指向的是模块内部的module.require,最终调用的是node的内部命令Module._load
用法
// foo.js
module.exports = {
foo:function(){}
}
// index.js
const { foo } = require('./foo.js')
foo();
es6 import & export
用法
语法和用法什么的就不写太详细了,作为前端这个太常用了
// foo.js
export const foo = function(){}
export const bar = function(){}
//index.js
import {foo,bar} from './foo.js'
import * as obj from './foo.js'
// foo.js
export default { a:1 }
//index.js
import obj from './foo.js'
console.log(obj.a)
特点及问题
node环境下 import需要在package.json开启type:module的时候才能使用,否则报错
- 如果开启了type:module,commonJS的require就用不了了,所以不要直接这样用。
- 另外也可以使用.mjs和.cjs的后缀,分别用于esm和cjs规范的文件,node会针对两者自动选择是哪个规范,这个看个人,要改文件名字,我不愿意。
浏览器环境下 需要配置script为type=module,才能使用,否则报错
- 本地调试,浏览器上直接跑会报跨域,可以起一个http服务再试
同一个文件里,要么使用export default,要么使用export,不要两个同时使用。否则import xx form './xx',则export出来的为undefined;import * as XX from './xx',则export default的为undefined
import和require混用
因为由上面分析我们知道,一个项目中是没办法直接同时使用这两个规范。要么只支持esm,要么只支持cjs。除非改文件名后缀。
实际上,很多npm的包都是cjs规范的,而我们开发都喜欢写esm规范的import,这就要祭出babel大法了。其实一般都是用babel来处理import和export,将它转译成cjs的规范,这样我们才能混用。
四种混用场景,大该讲一下babel的处理
- require和module.exports
不变,按照commonJS规范来
- require和export default
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _default = {
a: 1
};
exports.default = _default;
export default ,会把到导出的对象挂载到module.exports.default上,并加上__esModule标记。
- import和module.exports
"use strict";
var _moduleExports = _interopRequireDefault(require("./moduleExports"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
console.log(_moduleExports.default);
import实际会用require去加载module.exports,取的是加载过来对象的default属性。但是会做判断,如果加载过来的是__esModule,那么它本来就会被挂载default上;如果来的不是__esModule,那么我们就把obj挂载default上
- import和export default
由于步骤三做了处理,这里export default出来的对象会被挂载module.exports.default,而我们import刚好取的就是用require加载过来的module.exports的default属性,所以刚刚好。
es6和commonJS的区别
- es6 import是静态化的,在编译的时候就能确定依赖的关系;而commonJS是动态化的,需要在运行时在能确定依赖关系。
- es6 import进来的是只读的对象引用;而commonJS引入的是导出对象的深拷贝。
- es6 import如果在浏览器环境使用,script标签type=module,则是异步的,加载阶段不会阻塞dom解析,相当于defer,等dom解析完成再执行;commonJS是同步的,一定会等资源加载完再执行后面的逻辑
参考文档:
import和require如何在项目中混用
作者:西瓜太郎酱
commonJS规范 作者:阮一峰