# commonJs模块

1. **原文链接：**[**https://segmentfault.com/a/1190000011063732#articleHeader7**](https://segmentfault.com/a/1190000011063732#articleHeader7)
2. **原文链接：**[**http://www.ruanyifeng.com/blog/2015/05/commonjs-in-browser.html**](http://www.ruanyifeng.com/blog/2015/05/commonjs-in-browser.html)
3. **原文链接：**[**http://yijiebuyi.com/blog/7c8ffb3a58657e01e80f3bdc747473d2.html**](http://yijiebuyi.com/blog/7c8ffb3a58657e01e80f3bdc747473d2.html)
4. **原文链接：**[**https://zhaoda.net/webpack-handbook/commonjs.html**](https://zhaoda.net/webpack-handbook/commonjs.html)
5. 原文链接：<http://yijiebuyi.com/blog/7c8ffb3a58657e01e80f3bdc747473d2.html>

不久前，看到火狐在5月份将宣布支持js模块化,即会引入import，export方法。我自己一直都没有用过模块化的插件，比如commonJs,AMD,CMD，这些库的概念倒是都讲的是模块化操作，也就是模块化的编程。因为webpack具有这些插件的所有功能，并且更加强大，所以没有去了解这些插件库，其实webpack是怎样模块化的，我也搞不清楚，都是按照命令行操作，内部的实现没去弄学习，也没研究源码。

#### **模块化的好处：**

1. 功能的复用，写好的功能，可以直接通过模块引入，文件划分也清楚明了。
2. 大文件可以拆分为很多个模块，便于管理和维护。
3. 以前需要某个js插件的功能，就用script标签加载这个js 文件，有的时候就会加载很多个文件。script标签的加载是同步的，浏览器会停止渲染，同步加载这些js文件，这样会增加浏览器的响应时间。
4. 多个文件的命名冲突,全局变量的污染。

以前解决变量命名冲突的方法有，使用闭包，使用对象命名空间。

```javascript
//a.js
var obj_a= {
     test:1,
     say:function(){
          alert(1);
     }

}

//b.js

var obj_b={
     test:"str",
     say:function(){
          alert(144444);
     }

}
```

```javascript
var moudle=(function(){

    var a= 1;
    function say(){
       console.log(34)
    }

    return {a:a,say:say};
```

## CommonJS 模块，nodejs用的这个规范

* **模块定义导出**

**通过exports 或modules.exports导出模块,也就是定义模块。注意es6用的是export,不能直接给exports赋值,并且es6有 export {...} ,node里不可以 exports {...};切记不能弄混了。**

```javascript
//a.js
const a = 1;
let fun1 = function (x,y){

    return x + y ;
}


exports.a = a ;
exports.fun1 = fun1;
//注意   exports {a,fun1}; 不对，es6有 export {a，fun1},但是es6 不能export.a = a，这样导出。

//或
module.exports = {a , fun1};
```

在上面的例子中 ，exports 指向的就是module.exports;当使用模块化的时候，就已经声明 var expoets = module.exports = {};其中module指的就是当前的模块。打印出module就可以看到

```javascript
Module {
  id: '.',
  exports: {"a":1,"fun1":[Function]},
  parent: null,
  filename: '/Users/zss/node-Demo/my-app/testNOde/b.js',
  loaded: false,
  children: [],
  paths: 
   [ '/Users/zss/node-Demo/my-app/testNOde/node_modules',
     '/Users/zss/node-Demo/my-app/node_modules',
     '/Users/zss/node-Demo/node_modules',
     '/Users/zss/node_modules',
     '/Users/node_modules',
     '/node_modules' 
     ] 
   }
```

exports 是node 提供的一个变量指向module.exports，用来收集一些属性最后赋值给module.exports .这样一来，当我们在exports里导出变量a,再用module.exports 导出变量a,最后的结果是moudle.exports 的变量a.总之模块最终调用额是module.exports。

* **模块的分类，有两种模块**
* 一类为原生模块，例如http、path，加载的时候不用指明路径直接加载，速度很快。
* 一类为文件模块，动态加载的模块，也就是需要导入或是自己写。引入的时候需要指定模块的路径

**这两种模块加载的时候都会被缓存，也就是说第一次引用会加载，在引用的时候就会取缓存里的。**

* **模块的加载机制————模块的引用规则**

node的加载流程

1. 找目录下的文件名，然后加上扩展名称，依次按照“ .js  .node .json”查找，.node 和.json文件加上后缀名会快些。
2. 已上面的a.js 为例， 当找到a.js,首先读取内容包上一层function，避免暴露于全局中,这个function闭包有五个参数：exports，require,module，\_*filename,\\*\_dirname\_

```javascript
(function(exports,require,module,__filename,__dirname){

    const a = 1;
    let fun1 = function (x,y){

        return x + y ;
    }

    exports.module= {a,fun1};


});
```

**这就为什么在可以在js文件里直接用 require ,exports ,module,**\_\_*dirname,\_*\_filename.

node是读取缓存的，可以用如下的图来描述：

![](https://3888408026-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LgAR97naB5LLN11YQUv%2F-LgARCBqiK05WMt9Vl8b%2F-LgARPBvHgHDverLtEn4%2F3369101506-59ad214865a17_articlex.png?generation=1559265127897530\&alt=media)

CommonJs规范比较适合服务器端，浏览启端的需要异步加载，所以就有了CMD、AMD规范。

### 注意当导出一个模块的变量时，是对这个模块变量的缓存复制，也就是说模块块内的变量发生改变时，不影响导出的变量，读取的是缓存里的。这一点与es6的模块机制不同。

```javascript
// a,js
let a = 1;
let b = {"name":"str"};
const fun1 = function(){

      a++;
     return  a ;
};
exports.a=a;
exports.fun1=fun1;
exports.b=b; 

//或
module.exports={a,fun1};

b={test:"change"};

mpdule.exports.b.name == "str"  // true 没改变


//b.js
const obj = require("./a.js");
obj.fun1();//2
console.log(obj.a) // 1 没变
```
