# 模块化的区别

# 1. CommonJS

# 1.1 Usage

// 导入
const someFun= require('./moduleA');
someFun();

// 导出
module.exports = someFunc;

# 1.2 特点

  • CommonJS导出的是值的拷贝
  • CommonJS中最开始引用模块时会加载,之后会缓存在cache变量中

TIP

CommonJS导出的是值的拷贝,这句话其实没有那么神秘,就按照正常js运行时的逻辑来思考就可以

  1. 模块输出的是对象,属性值是简单数据类型时:
//name.js
let name = 'William';
setTimeout(() => { name = 'Yvette'; }, 300);
module.exports = { name };

//index.js
const { name } = require('./name');
console.log(name); //William
//name 是一个原始类型的值,更改不会影响导出对象
setTimeout(() => console.log(name), 500); //William

模块输出的是对象:

//name.js
let name = 'William';
let hobbies = ['coding'];
setTimeout(() => { 
    name = 'Yvette';
    hobbies.push('reading');
}, 300);
module.exports = { name, hobbies };

//index.js
const { name, hobbies } = require('./name');
console.log(name); //William
console.log(hobbies); //['coding']
/*
 * name 的值没有受到影响,因为 {name: name} 属性值 name 存的是个字符串
 *     300ms后 name 变量重新赋值,但是不会影响 {name: name}
 * 
 * hobbies 的值会被影响,因为 {hobbies: hobbies} 属性值 hobbies 中存的是
 *     数组的堆内存地址,因此当 hobbies 对象的值被改变时,存在栈内存中的地址并
       没有发生变化,因此 hoobies 对象值的改变会影响 {hobbies: hobbies} 
 * xx = { name, hobbies } 也因此改变 (复杂数据类型,拷贝的栈内存中存的地址)  
 */
setTimeout(() => {
    console.log(name);//William
    console.log(hobbies);//['coding', 'reading']
}, 500);

# 1.2 手写require

let fs = require('fs');
let path = require('path');
let b = myRequire('./b.js');
let cache = {}
function myRequire(mod) {
    if (cache[mod]) return cache[mod]; // 缓存
    let filename = path.join(__dirname, mod);
    let content = fs.readFileSync(filename, 'utf8');
    let fn = new Function('exports', 'require', 'module', '__filename', '__dirname', content + '\n return module.exports;');
    let var module = (cache[mod] = {
      exports: {},
    });
    return fn(module.exports, myRequire, module, __filename, __dirname);
}

# 2. ES6 模块化

# 2.1 Usage

// 导入
import { name } from './person.js';
// 导出
export const name = 'zfpx';

# 2.2 特点

  • ES6 module导出的是值的引用
  • ES6 模块是编译时输出接口

TIP

es6 中把module官方化了,那么import export 就是关键字了
对外接口只是一种静态定义,在代码静态解析阶段就会生成

//name.js
let name = 'William';
setTimeout(() => { name = 'Yvette'; hobbies.push('writing'); }, 300);
export { name };
export var hobbies = ['coding'];

//index.js
import { name, hobbies } from './name';
console.log(name, hobbies); //William ["coding"]
//name 和 hobbie 都会被模块内部的变化所影响
setTimeout(() => {
    console.log(name, hobbies); //Yvette ["coding", "writing"]
}, 500); //Yvette

# 3. 区别

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