es6 module和commonJs对比

es6 module

es6 module import

1.无法动态加载,import命令会被 JavaScript 引擎静态分析,先于模块内的其他语句执行

// 报错
if (x === 1) {
  import { foo } from 'module1';
} else {
  import { foo } from 'module2';
}

es6 module export

// export-default.js
export default function () {
  console.log('foo');
}

commonJs

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

commonJs导入require

1.require主要识别.js、 .json 或 .node等后缀,.js 文件会被解析为 JavaScript 文本文件, .json 文件会被解析为 JSON 文本文件。 .node 文件会被解析为通过 process.dlopen() 加载的编译后的插件模块,其他的后缀全部按js加载。
2..以 '/' 为前缀的模块是文件的绝对路径。
3.以 './' 为前缀的模块是相对于调用 require() 的文件的
4.require加载node_module时,向上逐级递归,直到根目录下的node_modules目录
新建index.js,内容如下

console.log(module.paths);

执行

node index.js

结果如下

5.每次导入模块,都会module将其封装,好处变量这些是不会污染全局,并且传入快捷变量 __filename 和 __dirname

(function(exports, require, module, __filename, __dirname) {
// 模块的代码实际上在这里
});

6.优先从缓存加载

function wrapper (script) {
    return '(function (exports, require, module, __filename, __dirname) {' + 
        script +
     '\n})'
}

function require(id) {
 var cachedModule = Module._cache[id];
  if(cachedModule){
    return cachedModule.exports;
  }
  
  const module = { exports: {} }

  // 这里先将引用加入缓存 后面循环引用会说到
  Module._cache[id] = module

  //当然不是eval这么简单
  eval(wrapper('module.exports = "123"'))(module.exports, require, module, 'filename', 'dirname')
  return module.exports
}

7.支持动态导入

if(true){
 require("./a/b");
}

commonJs导出

module.exports和export

//一个一个 导出
module.exports.age = 1
module.exports.foo = function(){}
exports.a = 'hello'

//整体导出
module.exports = { age: 1, a: 'hello', foo:function(){} }

//整体导出不能用`exports` 用exports不能在导入的时候使用
exports = { age: 1, a: 'hello', foo:function(){} }

差异

1.CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
CommonJS 模块输出的是值的拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值
CommonJS

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

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

JS 引擎对脚本静态分析的时候,遇到模块加载命令import,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值

// 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

2.CommonJS 模块是运行时加载,ES6 模块是编译时输出接口
3.CommonJS 模块的require()是同步加载模块,ES6 模块的import命令是异步加载,有一个独立的模块依赖的解析阶段

类型 加载方式 同步或异步 输出
CommonJS 动态导入 同步 输出值拷贝
es6module 静态导入 异步 输出值引用,需要的时候去加载模块取值
posted @ 2021-05-12 14:37  黑黑哈哈  阅读(423)  评论(0编辑  收藏  举报