ES6支持了原生的Moudle(简称:ESM),在此之前前端的模块化主要依靠CommonJS。
两者在使用上的直观区别是语法不同,但在底层的处理方式是不同的,主要的区别在于两者作用的阶段不一样。
-
CommonJS是在运行时加载的,
因为本质上CommonJS的require只是一个JS函数,只能在JS引擎执行代码时才生效
,而ESM是在JS引擎进行静态解析的时候生效的。 -
ESM输出的是值引用,CommonJS输出的是拷贝。假如我们用ESM声明了模块A,而B和C都引用了A,那么当B修改了A之后,C中的A也会跟着改变。而CommonJS规范在这种情况下,C就不会跟着改变。
这里就思考一个问题,日常开发大型项目,一般是使用了Webpack的。不管你使用什么规范,经过Webpack编译之后,都被集成在一个Bundle中了,并且经验证编译后的JS同样实现了上面的第2条效果。那么Webpack是如何实现的呢?
我们写个DEMO看一看
环境准备
首先,搭建一个简单的Webpack环境
新建一个项目,执行
npm init
npm i webpack --save
配置一下webpack
//webpack.config.js
const path = require('path');
module.exports = {
// JavaScript 执行入口文件
entry: './main.js',
output: {
// 把所有依赖的模块合并输出到一个 bundle.js 文件
filename: 'bundle.js',
// 输出文件都放到 dist 目录下
path: path.resolve(__dirname, './dist'),
}
};
复制代码
创建一个Html入口
// index.html
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<div id="app"></div>
<script src="./dist/bundle.js"></script>
</body>
</html>
复制代码
目录如下:
|– index.html
|– main.js
|– webpack.config.js
ESM
声明模块
//esm.js
export let name = 'congxiaobai'
export function show(content) {
name = content
console.log(name)
}
复制代码
引用
//main.js
import {show,name} from './ems'
// 执行 show 函数
console.log(name)
show('Webpack');
console.log(name)
复制代码
执行结果:
congxiaobai
Webpack
Webpack
看一下编译结果:
//bundle.js
(()=>{"use strict";
let o="congxiaobai";
console.log(o),
o="Webpack",
console.log(o),
console.log(o)})();
复制代码
CommonJS
声明模块
//common.js
let name = 'ws'
function show(content) {
name = content
console.log(name)
}
// 通过 CommonJS 规范导出 show 函数
module.exports = {
show:show,
name:name
};
复制代码
引用
//main.js
const show = require('./show.js');
console.log(show.name)
show.show('Webpack');
console.log(show.name)
复制代码
执行结果
congxiaobai
Webpack
congxiaobai
//bundle.js
(() => {
var o = {
298: o => {
let e = "congxiaobai";
o.exports = {
show: function (o) { e = o, console.log(e) },
name: e
}
}
},
e = {};
function n(r) {
var s = e[r];
if (void 0 !== s) return s.exports;
var t = e[r] = { exports: {} };
return o[r](t, t.exports, n), t.exports
}
(() => {
const o = n(298);
console.log(o.name),
o.show("Webpack"),
console.log(o.name)
})()
})();
复制代码
总结
由编译结果可知:
1. webpack最终将两种规范都编译成了立即执行函数,并通过闭包来实现commonjs的效果。
2.编译之后,对浏览器来说已经没有所谓的Moudle概念了,都在一个Bundle中了。