- CommonJS模块输出的是一个值的拷贝(浅拷⻉),一旦输出一个值,模块内部的变量就影响不到这个值,除非写成一个函数。ES6模块输出的是值的引用,但变量指向的地址是只读的,不能重新赋值,类似于const。
eg:
// 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 // lib.js模块加载以后,它的内部变化就影响不到输出的mod.counter了。这是因为mod.counter是一个原始类型的值,会被缓存。除非写成一个函数,才能得到内部变动后的值。 // lib.js var counter = 3; function incCounter() { counter++; } module.exports = { get counter() { return counter }, incCounter: incCounter, }; // main.js var mod = require('./lib'); console.log(mod.counter); // 3 mod.incCounter(); console.log(mod.counter); // 4
eg:
// 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 // main.js从lib.js输入变量obj,可以对obj添加属性,但是重新赋值就会报错。因为变量obj指向的地址是只读的,不能重新赋值,这就好比main.js创造了一个名为obj的const变量。 // lib.js export let obj = {}; // main.js import { obj } from './lib'; obj.prop = 123; // OK obj = {}; // TypeError
- CommonJS模块是运行时加载,它加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成。ES6模块是编译时输出接口,这种加载被称为编译时加载或者静态加载,即ES6模块可以在编译时就完成模块加载,效率要比CommonJS模块的加载方式高;当然这也导致了没法引用ES6模块本身,因为它不是对象。
eg:
// CommonJS模块 let { stat, exists, readFile } = require('fs'); // 等同于let _fs = require('fs'); let stat = _fs.stat; let exists = _fs.exists; let readfile = _fs.readfile;上面代码的实质是整体加载fs模块(即加载fs的所有方法),生成一个对象(_fs),然后再从这个对象上面读取3个方法。这种加载称为运行时加载,因为只有运行时才能得到这个对象,导致完全没办法在编译时做静态优化。
eg:
// ES6模块 import { stat, exists, readFile } from 'fs';上面代码的实质是从fs模块加载3个方法,其他方法不加载。这种加载称为编译时加载或者静态加载,即ES6模块可以在编译时就完成模块加载,效率要比CommonJS模块的加载方式高。当然这也导致了没法引用ES6模块本身,因为它不是对象。