编程领域中的模块化,就是遵守固定的规则,把一个大文件拆成独立并互相依赖的多个小模块。
把代码进行模块化拆分的好处:
① 提高了代码的复用性
② 提高了代码的可维护性
③ 可以实现按需加载

模块化常见的两种

CommonJS

每个文件都可以当作一个模块
在服务端:模块的加载时运行时同步加载的
在浏览器端:模块需要提前编译打包处理
在浏览器端编译打包需要用到 browserify。打包命令 browserify app.js -o build.js

ES6

依赖模块需要编译打包处理

语法:

导入模块:import
导出模块:export

分别暴露

  1. // 分别暴露模块
  2. export function foo() {
  3. console.log('foo()');
  4. }
  5. export function bar() {
  6. console.log('bar()');
  7. }
  8. export let arr = [1, 2, 3, 4, 5]

统一暴露

  1. // 统一暴露
  2. function fun() {
  3. console.log('fun()');
  4. }
  5. function fun2() {
  6. console.log('fun2()');
  7. }
  8. export { fun, fun2 }

默认暴露

  1. // 默认暴露
  2. export default {
  3. msg: 'hello......',
  4. fun: () => {
  5. console.log('aaaaaaaaaaaaa');
  6. }
  7. }

引入模块

  1. // 引入其他的模块
  2. // 如果是单个的js文件 引入时要加上后缀
  3. // 引入的是一个npm下载的包,就不需要加后缀
  4. import {foo, bar} from './module1.js'
  5. import {fun, fun2} from './module2.js'
  6. import module3 from './module3.js'
  7. import $ from 'jquery'
  8. import express from 'express'
  9. foo();
  10. bar();
  11. fun();
  12. fun2();
  13. console.log(module3.msg);;
  14. console.log(module3.fun());

ES6 中的模块化详细

模块作用域

每个模块都有自己的顶级作用域(top-level scope)。换句话说,一个模块中的顶级作用域变量和函数在其他脚本中是不可见的。
模块代码仅在第一次导入时被解析
如果同一个模块被导入到多个其他位置,那么它的代码只会执行一次,即在第一次被导入时。
在一个模块中,“this” 是 undefined
这是一个小功能,但为了完整性,我们应该提到它。
在一个模块中,顶级 this 是 undefined。
将其与非模块脚本进行比较会发现,非模块脚本的顶级 this 是全局对象:

  1. <script>
  2. alert(this); // window
  3. </script>
  4. <script type="module">
  5. alert(this); // undefined
  6. </script>

Import *

通常,我们把要导入的东西列在花括号 import {…} 中,就像这样:

  1. // 📁 main.js
  2. import {sayHi, sayBye} from './say.js';
  3. sayHi('John'); // Hello, John!
  4. sayBye('John'); // Bye, John!
  5. 但是如果有很多要导入的内容,我们可以使用 import * as 将所有内容导入为一个对象,例如:
  6. // 📁 main.js
  7. import * as say from './say.js';
  8. say.sayHi('John');
  9. say.sayBye('John');

乍一看,“通通导入”看起来很酷,写起来也很短,但是我们通常为什么要明确列出我们需要导入的内容?
比如说,我们向我们的项目里添加一个第三方库 say.js,它具有许多函数:
这里有几个原因。
现代的构建工具(webpack 和其他工具)将模块打包到一起并对其进行优化,以加快加载速度并删除未使用的代码。
比如说,我们向我们的项目里添加一个第三方库 say.js,它具有许多函数:

  1. // 📁 say.js
  2. export function sayHi() { ... }
  3. export function sayBye() { ... }
  4. export function becomeSilent() { ... }

现在如果我们只在我们的项目里使用了 say.js 中的一个函数:

  1. // 📁 main.js
  2. import {sayHi} from './say.js';

那么,优化器(optimizer)就会检测到它,并从打包好的代码中删除那些未被使用的函数,从而使构建更小。这就是所谓的“摇树(tree-shaking)”。
明确列出要导入的内容会使得名称较短:sayHi() 而不是 say.sayHi()。
导入的显式列表可以更好地概述代码结构:使用的内容和位置。它使得代码支持重构,并且重构起来更容易。
不用花括号的导入看起来很酷。刚开始使用模块时,一个常见的错误就是忘记写花括号。所以,请记住,import 命名的导出时需要花括号,而 import 默认的导出时不需要花括号。