common js、AMD、ES Module规范

common JS规范

是node js提出的一套模块化标准,在node js中所有模块化代码都必须要遵循common js的规范,这个标准约定了:

  • 一个文件就是一个模块
  • 每个模块都有单独的作用域
  • 通过module.exports的方式去导出成员
  • 通过require函数的方式去载入模块

如果我们想在浏览器用这个规范的话,会有问题。如果对node模块机制有了解的话,那应该知道common.js是以同步模式加载模块。因为node执行机制是在启动时去加载模块,执行过程中是不需要去加载的,它只会去使用到模块。所以说这种方式在node中不会有问题,但是如果放到浏览器端,在浏览器端使用common.js规范的话,必然导致效率低下。因为每次页面的加载都会导致大量的同步模式请求出现,所以说在早期的前端模块当中并没有选择common.js规范,而是专门为了浏览器端结合浏览器的特点重新设计了一个规范,这个规范叫做AMD (Asynchronous Module Definition)。


AMD(Asynchronous Module Definition)规范

翻译就是异步的模块定义规范,同期还推出了一个非常出名的库叫require.js。它实现了AMD规范,另外它本身就是一个强大的模块加载器,在AMD规范中,它约定每个模块都必须要通过 define函数去定义。define函数默认接受2个参数,也可以传递3个参数,如果传递3个参数,第一个参数就是模块的名字,在后期加载这个模块时候使用;第二个参数是个数组,用来声明这个模块的依赖项;第三个参数是个函数,函数的参数与前面的依赖项参数一一对应,每一项为这个依赖项导出的成员,这个函数的作用可以理解为为当前这个模块去提供一个私有的空间,如果需要这个模块需要向外部导出成员的话可以通过return的方式去实现。

// 定义一个模块
define('module1', ['jquery', './module2'], function ($, module2) {
   return {
     start: function () {
       $('body').animate({ margin: '200px' })
       module2()
     }
   }
 })

除此之外,require当中还提供了一个require函数去自动帮我们加载一个模块,它的用法与define函数类似,区别在于require函数只是用来加载模块,而define函数是用来定义模块的。当require.js去加载一个模块的话,它内部会自动去创建一个script标签去发送对应脚本文件的请求,并且执行相应的模块代码。

// 载入一个模块
require(['./module1'],function(module1) {
    module1.start()
})

目前绝大多数第三方库都支持AMD规范,也就是说AMD规范生态是比较好的,但是AMD使用起来相对比较复杂,编写代码的过程中除了业务的代码还要去使用到很多的define、require的一些操作模块的代码,这会导致代码的复杂程度有点提高。另外当项目的模块化分的特别细的话,对同一个页面当中js的文件请求次数就会特别多,从而导致页面效率就会比较低下,所以说AMD规范只能说是前端模块化演进道路上的一步,是一种妥协的实现方式,并不能算是最终的解决方案,但是在当时的一个环境背景下,它还是非常有意义的,它毕竟给了前端模块化提供了一个标准  。


有看过我前面文章的同学应该已经有了解前端模块化的发展过程,以及在这个过程当中出现过的一些标准,那尽管这些方式和标准也都实现了模块化,但是这些都多多少少存在着一些让开发者难以接受的问题。随着技术的发展,JavaScript的标准也在逐渐完善,而我们在模块化的实现方式相对以往已经有了很多的变化,现如今的前端模块化已经算是非常成熟了,而且目前大家针对于前端模块化的最佳实现方式也都基本统一了。

在node.js环境中回去遵循common.js的规范去组织模块,而浏览器环境中则采取ES Modules的规范,当然也有极少部分的例外情况出现。但是总的来说前端模块化目前算是统一成了common.js和ES Modules这两个规范,对于开发者而言,我们着重去掌握这两个规范就可以了。

common.js是node的内置模块系统,没有任何的环境问题,直接遵循common.js规范去使用require载入模块,通过module.export去导出模块。但是对于ES Modules相对来说复杂一些,因为ES Modules是EMCAScript 2015(ES6)定义的最新的模块系统,那也就是最近这几年才被定义的一个标准,所以肯定存在各种各样的环境兼容问题。最早在这标准被推出的时候,所有主流浏览器都是不支持这个特性的,但是随着webpack一系列打包工具的流行,这一规范才逐渐开始普及。截止目前来说,ES Modules已经基本上可以说最主流的前端模块化方案了。相比于AMD社区提出来的开发规范,ES Modules可以说是在语言层面实现了模块化,所以说它更为完善一点。

现如今的浏览器已经大多数都开始支持ES Modules特性了,原生支持也就意味着我们可以在以后直接去使用这个特性去开发网页应用。


ES Modules

因为很多浏览器已经支持这个特性,所以可以直接在script标签添加 module的属性,就可以ES Modules的标准去执行其中的JS代码了,它有以下新特性:

<!-- 1. ES Module 自动采用严格模式,忽略‘use strict’ -->
    <script type="module">
      console.log(this); // undefined
    </script>
<!-- 2. 每个 ES Module 都是运行在单独的私有作用域中 -->
    <script type="module">
      var foo = 100;
      console.log(foo); // 100
    </script>
    <script type="module">
      console.log(foo);  // 报错foo is not defined
    </script>
 <!-- 3.ES Module 是通过CORS的方式请求外部JS模块的 -->
    //下面的资源链接不支持CORS,访问时会报错跨域
    <script
      type="module"
      src="https://libs.baidu.com/jquery/2.0.0/jquery.min.js"
    ></script>

    //下面的资源链接支持CORS,正常访问
    <script
      type="module"
      src="https://unpkg.com/jquery@3.4.1/dist/jquery.min.js"
    ></script>
<!-- 4.ES Module 的script标签会延迟执行脚本,网页的加载过程默认对script标签时采用立即执行的机制,页面的渲染会等待脚本执行的完成才会继续往下渲染-->
    //普通script标签引入,此时会先执行js脚本再渲染页面
    <script src="./demo.js"> </script>
    <p>需要显示的内容</p>
    
    //添加module类型,会延迟执行脚本,等页面渲染完再去执行脚本
    <script type="module" src="./demo.js"> </script>
    <p>需要显示的内容</p>
// demo.js
alert('hello')

后续会出一篇特别讲解ES Modules的特性,敬请期待哟~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值