commonJs模块

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

模块化的好处:

  1. 功能的复用,写好的功能,可以直接通过模块引入,文件划分也清楚明了。

  2. 大文件可以拆分为很多个模块,便于管理和维护。

  3. 以前需要某个js插件的功能,就用script标签加载这个js 文件,有的时候就会加载很多个文件。script标签的加载是同步的,浏览器会停止渲染,同步加载这些js文件,这样会增加浏览器的响应时间。

  4. 多个文件的命名冲突,全局变量的污染。

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

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

}

//b.js

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

}
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 {...};切记不能弄混了。

//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就可以看到

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_

(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是读取缓存的,可以用如下的图来描述:

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

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

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

Last updated