# 认识CommonJS规范

运行时加载,因为只有运行时才能得到require的对象,完全没有办法在编译时进行“静态优化”

  1. CommonJS中规定每个文件是一个模块。将一个JavaScript文件直接通过script标签插入页面中与封装成CommonJS模块最大的不同在于,前者的顶层作用域是全局作用域,在进行变量及函数声明时会污染全局环境;而后者会形成一个属于模块自身的作用域,所有的变量及函数只有自己能访问,对外是不可见的。

  2. CommonJS中通过module.exports可以导出模块中的内容,模块内部会有一个module对象用于存放当前模块的信息。例子:

    module.exports = {
        name: 'calculater',
        add: function(a, b) {
            return a + b;
        }
    }
    // 简化书写(不推荐)
    exports.name = 'calculater';
    exports.add = function(a, b) {
        return a + b;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
  3. 在使用exports时要注意不要直接给exports赋值,否则会导致失效:

    exports = {
        name: 'calculater'
    }
    // 上面的代码由于对exports进行赋值操作,使其指向了新的对象,module.exports却仍然是原来的空对象,因此name属性并不会被导出。
    
    1
    2
    3
    4
  4. commonJS用同步的方式加载模块。在服务端,模块文件都存在本地磁盘,读取非常快,所以这样做不会有问题。但是在浏览器端,限于网络原因,更合理的方案是使用异步加载。

  5. 当我们require一个模块时会有两个情况:

require是Node的语法,浏览器无法识别。运行时加载模块,具有动态加载的功能。

  • require模块第一次被加载。这时会首先执行该模块,然后导出内容。
  • require的模块曾被加载过。这时模块的代码不会再次执行,而是直接导出上次执行后得到的结果。

# CommonJS模块化的特点:

  • 加载机制:输入的是被输出的值的拷贝,也就是说:一旦输出一个值,模块内部的变化就影响不到这个值。
  • 所有代码都运行在模块作用域,不会污染全局作用域
  • 模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。
  • 模块加载顺序,按照其在代码中出现的顺序。

同步加载代码,在浏览器会发生堵塞问题,造成页面无响应,所以浏览器不太适合用CommonJS来加载。

  • CommonJS规范对浏览器和服务器端的不同之处:
    • 服务器端所有的模块都存放在本地硬盘中,同步加载完成才能执行后续操作,等待时间就是硬盘的读取时间。
    • 浏览器,所有的模块都放在服务器端,等待时间取决于网速的快慢,可能要等很长时间,浏览器处于”假死”状态。

TIP

  1. 每一个文件就是一个模块,拥有自己独立的作用域,变量,以及方法等,对其他的模块都不可见。CommonJS规范规定:每个模块内部,module变量代表当前模块。这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。加载某个模块,其实是加载该模块的module.exports属性。require方法用于加载模块。
  2. 模块加载的顺序按照其在代码中出现的顺序