js模块化规范

目前流行的js模块化规范

  • CommonJS
  • AMD
  • CMD
  • UMD
  • ES6的模块系统

模块化是什么

简单来说,一个文件就是一个模块,这个文件内的作用域唯一,可以向外暴露变量,函数等。模块化的出现减少了代码的繁琐,利于代码复用和日后维护。

NodeJS

在nodeJS出现前,前端没有模块化的概念,NodeJS出现后,使用的是CommonJS的模块化规范,目前主流的前端框架vue/react都是基于node来构建的。

CommonJS

NodeJS使用的是CommonJS的模块化规范,CommonJS有四个核心的比较重要的环境变量:moduleexportsrequireglobal

module,exports
module.exports = {
//...............
}
 
以及
var math = require('XXXX');

module变量代表当前模块。这个变量是一个对象,它的exports属性(即module.exports)是对外的接口,不建议直接使用exports。在其他模块需要引入的地方使用require’来引入。

module.exports和exports的区别

两者都可以用来导出,exports实际也是使用了module.exports导出,因为node在内部对exports进行了赋值

var exports = module.exports;

exports在导出的时候,需要添加属性或者方法,因为它指向的是module.exports,module.exports变量本就是一个对象,实际导出也是导出这个变量。不可以直接给exports赋值一个变量或者函数,这是错误的。。。

exports.XXX = '我是错误的导出'//正确的
exports.XXX = function(){ }; //正确的
modules对象的属性
  • module.id - 模块的识别符,通常是带有绝对路径的模块文件名
  • module.filename - 模块的文件名,带有绝对路径
  • module.loaded - 返回一个boolean值,表示模块是否已经完成加载
  • module.parent - 返回一个对象,表示调用该模块的模块
  • module.children - 返回一个数组,表示该模块内用到的其他模块
  • module.exports - 表示模块对外输出的值
require

require用来加载模块,所有加载的模块都会缓存保存到require.cache中

使用require加载模块的时候,必须加 ./ 路径,不加的话只会去node_modules文件找。

// 引用自定义的模块时,参数包含路径,可省略.js
var math = require('./math');
 
// 引用核心模块时,不需要带路径
var http = require('http');
reuqire使用时的内部处理流程
  1. 在执行到require语句时,先检查是否存在这个模块的缓存
  2. 如果没找到缓存,那么就会创建一个新的module实例,并且缓存下exports导出的值,如果没发现exports的模块会报错
  3. 如果缓存存在的话,执行module.load()这个方法,去加载这个模块,读取文件内容后,使用module.compile()执行文件代码
  4. 如果解析过程中,出现异常,就从缓存中删除这个模块
  5. 如果没有出现异常,最后返回这个模块的module.exports
global

global对象是nodejs的全局对象,上边挂在了一些最基本的全局方法。

CommonJS模块的缓存

第一次加载模块,node会加载并缓存下来,之后使用的时候直接从缓存中读取module.exports的值。

缓存是根据绝对路径识别模块的,如果模块名相同,但是保存的路径不同,require命令还是会重新加载该模块。

加载模块只会在第一次,后面如果需要重新加载可以通过清除缓存的方式。

CommonJS的缺点

CommonJS的加载方式是同步加载,意味着只有前面执行完成才会继续执行。

同步就会存在一个问题,加载的速度收到影响。

NodeJS主要用于服务器编程,模块文件一般都已经存于本地硬盘中,所以加载速度比较快,不用考虑非同步加载的方式

浏览器环境,要从服务器端加载模块,这时必须要采用非同步模式,因此浏览器端一般采用AMD规范。

webpack

NodeJS是CommonJS规范服务器端的实现,webpack也是CommonJS的形式书写。同步加载,服务器端从磁盘中读取速度快,运行在服务器端没有问题

AMD

  • AMD是异步加载模块,推崇依赖前置,js可以提前知道所有的依赖模块,立即加载,加载完模块会立即执行,所有模块加载完之后进入require函数,执行主逻辑。

  • 依赖模块的执行顺序和开发人员写的不一样,哪一个模块网速好先下载哪个就先执行,但是主逻辑一定是所有模块加载完成后才执行。

  • AMD提前执行。

  • AMD用户体验好,不延迟执行,依赖模块提前加载完毕。

为什么服务器端可以同步加载,浏览器端不能同步加载,需要异步加载
var math = require('math');
math.add(2,3)

解析:第二行代码在第一行之后运行,必须等到math.js加载完成后运行,如果加载时间特别特别长,整个程序就会卡顿。这里的requrie是同步加载的。浏览器的模块都在服务器端,等待时间取决于网络速度的快慢,等待的时间越长,浏览器响应的时间越长,甚至造成“假死”的状态。服务器端的模块放在本地硬盘中,同步加载读取的时间很快,几乎不会产生什么影响。

CMD

  • CMD是异步加载模块,推崇依赖就近,模块解析为字符串后才能知道依赖哪些模块
  • CMD加载完某个模块后并不执行,只是下载,在所有模块加载完成后进入主逻辑,遇到require语句的时候才执行对应的模块。依赖模块的执行顺序和开发人员写的一样。
  • CMD延迟执行。
  • CMD性能好,按需加载,当用户有需要再执行。
    //AMD默认推荐的是
    define(['./a', './b'], function (a, b) { //依赖前置,必须一开始就写好
        a.doSomething()
        b.doSomething()
    })
    //CMD默认推荐的是
    define(function (require, exports, module) {
        var a = require('./a')
        a.doSomething()
        var b = require('./b') //依赖就近,按需加载,需要哪个写哪个
        b.doSomething()
    })
AMD和CMD最大的区别是对依赖模块的执行时机处理不同注意不是加载的时机或者方式不同

ES6模块化

ES6静态编译,在编译的时候就能确定依赖,编译的时候输出接口。export输出指定代码,import某个值不是整个模块。

ES6与CommonJS的区别

  • CommonJS模块输出的是值拷贝,内部的变化影响不到值的变化。

  • ES6模块输出的是值引用,原始值变化,加载的值也会跟着变化,ES6模块是动态引用,并且不会缓存值。

  • CommonJS模块就是对象,输入时先加载整个模块,生成一个对象,然后从对象读取方法。

  • ES6模块不是对象,export输出指定代码,import导入加载某个值,而不是整个模块。

  • 关于模块顶层的this指向问题,在CommonJS顶层,this指向当前模块;而在ES6模块中,this指向undefined。

  • ES6模块当中,是支持加载CommonJS模块的。但是反过来,CommonJS并不能 require ES6模块,在NodeJS中,两种模块方案是分开处理的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值