编程领域中的模块化,就是遵守固定的规则,把一个大文件拆成独立并互相依赖的多个小模块。
把代码进行模块化拆分的好处:
① 提高了代码的复用性
② 提高了代码的可维护性
③ 可以实现按需加载
CommonJS
每个文件都可以当作一个模块
在服务端:模块的加载时运行时同步加载的
在浏览器端:模块需要提前编译打包处理
在浏览器端编译打包需要用到 browserify。打包命令 browserify app.js -o build.js
ES6
依赖模块需要编译打包处理
语法:
导入模块:import
导出模块:export
分别暴露
// 分别暴露模块
export function foo() {
console.log('foo()');
}
export function bar() {
console.log('bar()');
}
export let arr = [1, 2, 3, 4, 5]
统一暴露
// 统一暴露
function fun() {
console.log('fun()');
}
function fun2() {
console.log('fun2()');
}
export { fun, fun2 }
默认暴露
// 默认暴露
export default {
msg: 'hello......',
fun: () => {
console.log('aaaaaaaaaaaaa');
}
}
引入模块
// 引入其他的模块
// 如果是单个的js文件 引入时要加上后缀
// 引入的是一个npm下载的包,就不需要加后缀
import {foo, bar} from './module1.js'
import {fun, fun2} from './module2.js'
import module3 from './module3.js'
import $ from 'jquery'
import express from 'express'
foo();
bar();
fun();
fun2();
console.log(module3.msg);;
console.log(module3.fun());
ES6 中的模块化详细
模块作用域
每个模块都有自己的顶级作用域(top-level scope)。换句话说,一个模块中的顶级作用域变量和函数在其他脚本中是不可见的。
模块代码仅在第一次导入时被解析
如果同一个模块被导入到多个其他位置,那么它的代码只会执行一次,即在第一次被导入时。
在一个模块中,“this” 是 undefined
这是一个小功能,但为了完整性,我们应该提到它。
在一个模块中,顶级 this 是 undefined。
将其与非模块脚本进行比较会发现,非模块脚本的顶级 this 是全局对象:
<script>
alert(this); // window
</script>
<script type="module">
alert(this); // undefined
</script>
Import *
通常,我们把要导入的东西列在花括号 import {…} 中,就像这样:
// 📁 main.js
import {sayHi, sayBye} from './say.js';
sayHi('John'); // Hello, John!
sayBye('John'); // Bye, John!
但是如果有很多要导入的内容,我们可以使用 import * as 将所有内容导入为一个对象,例如:
// 📁 main.js
import * as say from './say.js';
say.sayHi('John');
say.sayBye('John');
乍一看,“通通导入”看起来很酷,写起来也很短,但是我们通常为什么要明确列出我们需要导入的内容?
比如说,我们向我们的项目里添加一个第三方库 say.js,它具有许多函数:
这里有几个原因。
现代的构建工具(webpack 和其他工具)将模块打包到一起并对其进行优化,以加快加载速度并删除未使用的代码。
比如说,我们向我们的项目里添加一个第三方库 say.js,它具有许多函数:
// 📁 say.js
export function sayHi() { ... }
export function sayBye() { ... }
export function becomeSilent() { ... }
现在如果我们只在我们的项目里使用了 say.js 中的一个函数:
// 📁 main.js
import {sayHi} from './say.js';
那么,优化器(optimizer)就会检测到它,并从打包好的代码中删除那些未被使用的函数,从而使构建更小。这就是所谓的“摇树(tree-shaking)”。
明确列出要导入的内容会使得名称较短:sayHi() 而不是 say.sayHi()。
导入的显式列表可以更好地概述代码结构:使用的内容和位置。它使得代码支持重构,并且重构起来更容易。
不用花括号的导入看起来很酷。刚开始使用模块时,一个常见的错误就是忘记写花括号。所以,请记住,import 命名的导出时需要花括号,而 import 默认的导出时不需要花括号。