模块化学习笔记| 青训营笔记

64 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天

CommonJS

概述

Node 应用由模块组成,采用 CommonJS 模块规范。每个文件就是一个模块,有自己的作用域。在一个文件中定义的变量、函数、类,都是私有的,对其他文件不可见。在服务器端,模块的加载是运行时同步加载的;在浏览器端,模块需要提前编译打包处理

特点

  • 所有代码都运行在模块作用域,不会污染全局作用域。
  • 模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。
  • 模块加载的顺序,按照其在代码中出现的顺序。

基本语法

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

模块的加载机制

CommonJS 模块的加载机制是,输出的是被输出的值的拷贝。也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。这点与ES6 模块化有重大差异,请看下面这个例子:

// lib.js
var counter = 3;
function incCounter() {
  counter++;
}
module.exports = {
  counter: counter,
  incCounter: incCounter,
};

上面代码输出内部变量 counter 和改写这个变量的内部方法 incCounter。

// main.js
var counter = require('./lib').counter;
var incCounter = require('./lib').incCounter;

console.log(counter);  // 3
incCounter();
console.log(counter); // 3

上面代码说明,counter 输出以后,lib.js 模块内部的变化就影响不到 counter 了。这是因为 counter 是一个原始类型的值,会被缓存。除非写成一个函数,才能得到内部变动后的值

ES6 模块与 CommonJS 模块的差异

它们有两个重大差异:

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

下面重点解释第一个差异,我们还是举上面那个 CommonJS 模块的加载机制例子:

// lib.js
export let counter = 3;
export function incCounter() {
  counter++;
}
// main.js
import { counter, incCounter } from './lib';
console.log(counter); // 3
incCounter();
console.log(counter); // 4

ES6 模块的运行机制与 CommonJS 不一样。ES6 模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块