美文网首页模块化模块化
JS模块化初探-CommonJs、AMD、CMD和Requist

JS模块化初探-CommonJs、AMD、CMD和Requist

作者: 放风筝的小小马 | 来源:发表于2017-07-16 17:09 被阅读169次

什么是模块化?

简单理解:将各个功能封装为独立的模块,当需要某个功能时,只需要加载相应的模块即可

为什么出现模块化?

随着技术的发展,web应用的代码日益增大,由于JavaScript的语言特性(在ES5之前js并没有像java一样拥有类和模块的语言等特性),导致其无法驾驭规模如此大的代码,因此迫切需要通过一种方式来模拟出类似于模块的功能,所以便出现了模块化

模块化的价值

  • 解决命名冲突
  • 便于依赖管理
  • 提高代码可读性
  • 代码解耦,提高复用性

没有出现模块化时,代码存在的问题

  • 命名冲突
    假如封装了一个函数叫fun1,该函数被用于项目中,那么fun1这个名字就不能被其他人重新用于创建函数或变量, 否则会出现命名冲突
  • 文件依赖问题
    就是各个js文件中的依赖关系只能通过人肉的方式进行组织,文件依赖没有很好的管理起来

注意: 到这里时查看前端模块化开发的价值这篇文章

CommonJS、AMD和CMD

一个模块就是实现特定功能的文件,有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块。模块开发需要遵循一定的规范,各行其是就都乱套了,由此便出现了CommonJS、AMD、CMD等规范(注意:这些都是规范,规范的作用是让人来遵守的,因此出现了很多支持这些规范的工具)

注意:到这里时,阅读以下文章了解下这三者之间的关系:

CommonJS介绍

阅读这篇文章:
CommonJS规范
目标:

  • 了解CommonJS的特点
  • 了解CommonJS模块规范与AMD规范的区别

注意:

  • 如果对于文章中出现的CommonJS模块编写语法不熟悉,先不要深究,等进行实践时在进行深入了解,先只了解其特点

Node应用由模块组成,采用CommonJS模块规范。
规范特点:

  • CommonJS规范加载模块是同步的,也就是只有加载完成后,才能执行后面的操作,由于这个特性,CommonJS模块一般只用于服务器端,而不用于浏览器端
  • 所有代码均运行在模块作用域,不会污染全局变量;也就是说模块内部的变量,无法被外部模块调用,除非将其定义为global对象的属性
  • 模块加载顺序,按照其在代码中的书写顺序进行加载
  • 模块可以多次加载,但是只会在第一次加载时运行一次,然后将运行结果缓存,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存

语法特点

  • 定义模块: 定义模块 根据CommonJS规范,一个单独的文件就是一个模块。每一个模块都是一个单独的作用域,也就是说,在该模块内部定义的变量,无法被其他模块读取,除非定义为global对象的属性
  • 模块输出:模块只有一个出口——module.exports对象,我们需要把模块希望输出的内容放入该对象上
  • 加载模块:加载模块使用require方法,该方法读取一个文件并执行,返回文件内部的module.exports对象

代码示例

// 模块定义 myModel.js

var name = 'Byron';
function printName(){
    console.log(name);
}
function printFullName(firstName){
    console.log(firstName + name);
}
module.exports = {
    printName: printName,
    printFullName: printFullName
}

// 在其他文件中加载模块
var nameModule = require('./myModel.js');
nameModule.printName();

AMD规范

AMD 即 Asynchronous Module Definition异步模块定义),它是一个在浏览器端进行模块化开发的规范

因为该规范不是JavaScript原生支持的,因此使用该规范进行开发时,需要用到对应的库函数,如:RequireJS

RequireJS主要解决两个问题:

  • 多个js文件可能有依赖问题,被依赖的文件需要早于依赖它的文件被加载
  • js加载的时候浏览器会停止渲染,加载的文件越多,页面失去响应的时间越长

语法

定义模块
AMD规范定义了define()函数,它是一个全局变量,用于定于模块,语法:
define(id?, dependencies?, factory);

  • id:可选参数,用于定于模块的标识,如果没有提供该参数,模块名则为脚本文件名
  • dependencies:当前模块依赖的模块名称数组
  • factory:工厂方法,模块初始化要执行的函数或对象,如果是函数,它应该只被执行一次;如果是对象,此对象应该为模块的输出值

加载模块
在页面上使用require()函数加载模块,语法:
require([dependencies], function(){});
requiire接收两个参数:

  1. 第一个参数是一个数组,表示所依赖的模块
  2. 第二个参数是一个回调函数,当前面指定的模块都加载成功后,它将被调用。加载的模块会以参数的形式传入该函数,从而在函数内部就可以使用这些模块
    注意: require()函数在加载依赖的模块时是异步加载的,这样浏览器不会失去响应,它指定的回调函数,只有前面的模块加载完成后才会执行,*解决了依赖问题

例子

// 定义一个myModule.js模块
define(['dependency1', 'dependency2'], function(){
  var name = 'hexon';
  function sayName(){
    console.log(name);
  }
  return {
    sayName: sayName
  };
});

// 加载模块
require(['myModule'], function(my){
  my.sayName();  
});

示例解析

  • 通过define定义个模块,该模块的名字没有写明
  • 'dependency1'和''dependency2'为该模块所依赖的文件
  • 当依赖的文件加载完成后,执行function,返回一个对象,对象中包含需要提供给外部调用的内容,这里提供了一个sayName方法
  • 通过require加载模块,'myModule'为需要加载的模块,my为'myModule'模块的别名,通过my来调用myModule模块内的资源

参考文章:AMD (中文版):

AMD规范与CommonJS规范的兼容性

CommonJS规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。AMD规范则是非同步加载模块,允许指定回调函数。由于Node.js主要用于服务器编程,模块文件一般都已经存在于本地硬盘,所以加载起来比较快,不用考虑非同步加载的方式,所以CommonJS规范比较适用。但是,如果是浏览器环境,要从服务器端加载模块,这时就必须采用非同步模式,因此浏览器端一般采用AMD规范。

AMD规范使用define方法定义模块,下面就是一个例子:

define(['package/lib'], function(lib){
  function foo(){
    lib.log('hello world!');
  }

  return {
    foo: foo
  };
});

AMD规范允许输出的模块兼容CommonJS规范,这时define方法需要写成下面这样:

define(function (require, exports, module){
  var someModule = require("someModule");
  var anotherModule = require("anotherModule");

  someModule.doTehAwesome();
  anotherModule.doMoarAwesome();

  exports.asplode = function (){
    someModule.doTehAwesome();
    anotherModule.doMoarAwesome();
  };
});

CMD规范

CMD即Common Module Definition通用模块定义,CMD规范是国内发展而来的,CMD的代表库有SeaJS,SeaJS要解决的问题和RequireJS一样,只不过在模块定义方式和模块加载时机上有所不同,SeaJS是需要时才去加载,而RequireJS是预先加载好
语法
SeaJS推崇一个模块一个文件,遵循统一写法,使用define关键字定义一个模块
define
define(factory)

Module Context

define(function(require, exports, module) {

  // The module code goes here

});

示例代码
A typical sample

math.js

define(function(require, exports, module) {
  exports.add = function() {
    var sum = 0, i = 0, args = arguments, l = args.length;
    while (i < l) {
      sum += args[i++];
    }
    return sum;
  };
});

increment.js

define(function(require, exports, module) {
  var add = require('math').add;
  exports.increment = function(val) {
    return add(val, 1);
  };
});

program.js

define(function(require, exports, module) {
  var inc = require('increment').increment;
  var a = 1;
  inc(a); // 2

  module.id == "program";
});

参考:CMD介绍

相关文章

  • JS模块化初探-CommonJs、AMD、CMD和Requist

    什么是模块化? 简单理解:将各个功能封装为独立的模块,当需要某个功能时,只需要加载相应的模块即可 为什么出现模块化...

  • js模块化相关

    js模块化编程之彻底弄懂CommonJS和AMD/CMD!

  • js模块化

    js的模块化大致分为4种规范 amd cmd commonjs 和es6模块化 1.amd规范 amd规范又叫异步...

  • js的模块方案:CommonJS、AMD和CMD

    什么是CommonJS、AMD和CMD CommonJS、AMD和CMD都是js的模块加载方案,JS在最初设计的时...

  • 一次性搞懂 CommonJS, AMD, CMD 等模块化规范

    1 常见的模块化规范 CommonJs (Node.js) AMD (RequireJS) CMD (SeaJS)...

  • 前端工程化的一些理解

    一、模块化 主要是js模块化,可以使用CommonJS、AMD、CMD等模块化规范,其中的区别是CommonJS对...

  • js模块化规范

    一、js模块化1、模块化规范: script CommonJS AMD CMD ES6 modules 2、scr...

  • 2-1、模块化

    一、JS模块化 (1)命名空间 (2)CommonJS (3)AMD (4)CMD (5)UMD (5)ESM (...

  • 归档

    AMD、CMD、CommonJs、ES6的对比 他们都是用于在模块化定义中使用的,AMD、CMD、CommonJs...

  • JS模块化

    模块化规范:CommonJS,AMD,CMD,UMD,ES6 Module CommonJS CommonJS是服...

网友评论

    本文标题:JS模块化初探-CommonJs、AMD、CMD和Requist

    本文链接:https://www.haomeiwen.com/subject/ilwtkxtx.html