乐趣区

模块化解读

分类

主要介绍以下几种模块化方案

  • ES6
  • CommonJS
  • AMD

ES6

介绍:ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。

特点:

  1. 尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量,
  2. ES6 模块不是对象,而是通过 export 命令显式指定输出的代码,再通过 import 命令输入,定义了输出的对外接口
  3. 这种加载称为“编译时加载”或者静态加载,即 ES6 可以在编译时就完成模块加载,效率要比 CommonJS 模块的加载方式高。当然,这也导致了没法引用 ES6 模块本身,因为它不是对象
  4. 编译时加载,使得静态分析成为可能

语法规则

  1. 另外,export语句输出的接口,与其对应的值是动态绑定关系,即通过该接口,可以取到模块内部实时的值
  2. export命令可以出现在模块的任何位置,只要处于模块顶层就可以。如果处于块级作用域内,就会报错
  3. export 命令后面,使用大括号指定所要输出的一组变量(包括变量,匿名函数,具名函数)看下这里错误的例子,变量输出类似
// 报错
function f() {}
export f;

// 正确
export function f() {};

// 正确
function f() {}
export {f};

看看 import

  1. import命令输入的变量都是只读的,因为它的本质是输入接口, 但是导入对象即使可以修改属性,也是不建议的
  2. 一般会把 import 语句放在处理的方法前,不过 import 命令具有提升效果,会提升到整个模块的头部,首先执行,也不会导致报错
foo();

import {foo} from 'my_module';

3.import是静态执行,所以不能使用表达式和变量,这些只有在运行时才能得到结果的语法结构
4. 通过 Babel 转码,CommonJS 模块的require 命令和 ES6 模块的 import 命令,可以写在同一个模块里面,但是最好不要这样做。因为 import 在静态解析阶段执行,所以它是一个模块之中最早执行的
5. 实现模块整体加载
6. 使用 export default 指定默认输出,对应的import 语句不需要使用大括号

import 函数

  • 支持动态加载模块,运行时处理模块是优点,但是动态加载不能丢
  • 支持异步,做按需加载
  • 此时就类似于 require 加载

看一段比较秀的

async function main() {const myModule = await import('./myModule.js');
  const {export1, export2} = await import('./myModule.js');
  const [module1, module2, module3] =
    await Promise.all([import('./module1.js'),
      import('./module2.js'),
      import('./module3.js'),
    ]);
}
main()

1. 防止异步阻塞
2.import 返回值解构

ES6 与 CommonJS 的差异

  • CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用
  • CommonJS 模块是运行时加载,ES6 模块是编译时输出接口

CommonJS

  • CommonJS 的一个模块,就是一个脚本文件。require命令第一次加载该脚本,就会执行整个脚本,然后在内存生成一个对象,该对象关注三个属性。

    • id: 模块名
    • exports: 输出的接口
    • loaded: 脚本是否执行完毕

所以再次 require 不会执行脚本,只会获取对应的结果和拷贝值

  • 加载时执行
  • 语法

    • module.exports = valueexports.xxx = value
    • require(xxx), 如果是第三方模块,xxx 为模块名;如果是自定义模块,xxx 为模块文件路径

AMD

async 开头的词一般都有异步含义,node api 里比较多,在浏览器加载模块就是采用这种方案

  • 使用 define 定义模块
  • 使用 require 使用模块,处理逻辑异步进行

模块化文章参考 https://es6.ruanyifeng.com/#d…

一些问题

  1. 按需加载
import {stat, exists, readFile} from 'fs';

这里只加载需要模块,其它不加载,这种按需加载是如何实现的(指的是最后打包文件中不含非相关代码),在项目中有哪些按需加载的例子

  1. deferasync 的区别是
  2. 在 node.js 中使用 ES6 的模块化
  3. 如何处理循环加载

    1. ES6 会在编译时分析模块,相当于在执行上下文中分析 VO,在循环加载时候看定义方式,没有变量提升的一般会导致报错
    2. 对于 CommonJS 而言,循环加载的执行过程是:

      1. 加载别的模块,js 模块执行权变为新模块
      2. 循环过程不会对已经加载模块重复运行,只会获取缓存结果
  4. 顺便说一下 webpack 的会有循环打包吗
退出移动版