本文由云+社区发表

模块化是指把一个复杂的系统分解到一个一个的模块。

模块化开发的优点

(1)代码复用,让我们更方便地进行代码管理、同时也便于后面代码的修改和维护。

(2)一个单独的文件就是一个模块,是一个单独的作用域,只向外暴露特定的变量和函数。这样可以避免污染全局变量,减少变量命名冲突。

js模块化规范有:CommonJS、AMD、CMD、ES6的模块系统。本文将依次介绍下每个规范。

0.早期:用script来引入js模块

<script type="text/javascript" src="a.js"></script>
<script type="text/javascript" src="b.js"></script>
<script type="text/javascript" src="c.js"></script>
<script type="text/javascript" src="d.js"></script>

缺点:

(1)加载的时候会停止渲染网页,引入的js文件越多,网页失去响应的时间越长;

(2)会污染全局变量;

(3)js文件之间存在依赖关系,加载是有顺序的,依赖性最大的要放到最后去加载;当项目规模较大时,依赖关系变得错综复杂。

(4)要引入的js文件太多,不美观,代码难以管理。

1.CommonJS 规范

服务器端模块的规范,由nodejs推广使用。该规范的核心思想是:允许模块通过require方法来同步加载所要依赖的其他模块,然后通过 exports 或module.exports 来导出需要暴露的接口。

CommonJS 还可以细分为 CommonJS1 和 CommonJS2,区别在于 CommonJS1 只能通过 exports.xx = xx 的方式导出,CommonJS2 在 CommonJS1 的基础上加入了module.exports = xx 的导出方式。 CommonJS 通常指 CommonJS2。

采用CommonJS 规范导入导出:

// 导出
module.exports = moduleA.someFunc;
// 导入
const moduleA = require('./moduleA');

实例:

//math.js
var num = 0;
function add(a, b) {
return a + b;
}
module.exports = {
//需要向外暴露的变量、函数
num: num,
add: add
}

可以这样加载:

//引入自定义的模块时,参数包含路径,可省略.js
//引入核心模块时,不需要带路径,如var http = require("http");
var math = require('./math');
math.add(1, 2)//3

实际上,从上面的例子就可以看出,math.add(1,2)必须要等待math.js加载完成,即require是同步的。

在服务器端,模块文件保存在本地磁盘,等待时间就是磁盘的读取时间。但对于浏览器而言,由于模块都放在服务器端,等待时间取决于网上的快慢。因此更合理的方案是异步加载模块。

缺点:

(1)不能并行加载模块,会阻塞浏览器加载;

(2)代码无法直接运行在浏览器环境下,必须通过工具转换成标准的 ES5;

2.AMD和require.js

AMD:异步模块定义。上面已经介绍过,CommonJS是服务器端模块的规范,主要是为了JS在后端的表现制定的,不太适合前端。而AMD就是要为前端JS的表现制定规范。由于不是JavaScript原生支持,使用AMD规范进行页面开发需要用到对应的库函数,也就是require.js(还有个js库:curl.js)。实际上AMD 是 require.js在推广过程中对模块定义的规范化的产出。

AMD采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。

require.js也采用require()语句加载模块,但是不同于CommonJS:

// 定义一个模块
define('module', ['dep'], function (dep) {
return exports;
}); // 导入和使用
require(['module'], function (module) {
});

上面示例中的代码改写成AMD形式:

math.js定义一个模块:

define('math', ['jquery'], function (jquery) {//引入jQuery模块
return {
add: function (x, y) {
return x + y;
}
};
});

导入和使用:

require(['math'], function (math) {
math.add(1, 2)
})

math.add()与加载math模块不是同步的,不会阻塞浏览器的加载。

3.CMD和sea.js

CMD:通用模块定义。

国内的玉伯大佬写了sea.js,实际上CMD就是 sea.js在推广过程中对模块定义的规范化的产出。

define(function (require, exports, module) {
// 模块代码
});

说明:

require:可以把其他模块导入进来的一个参数;

exports:可以把模块内的一些属性和方法导出的;

module: 是一个对象,上面存储了与当前模块相关联的一些属性和方法。

上面示例中的代码改写成AMD形式:

define(function (require, exports, module) {
var add = function (a, b) {
return a + b;
}
exports.add = add;
}) //导入和使用
seajs.use(['math.js'], function (math) {
var sum = math.add(1, 2);
});

CMD与AMD的不同的在于:

(1)AMD推崇依赖前置;CMD推崇依赖就近,只有在用到某个模块的时候再去require:

//AMD推崇的依赖关系前置:在定义模块时就要声明要依赖的模块
define(['a', 'b', 'c', 'd'], function (a, b, c, d) { // 依赖必须一开始就写好
a.doSomething()
// 此处省略100行
...
b.doSomething()
...
}) //CMD推崇依赖就近,按需加载,只有在用到某个模块时再去require
define(function (require, exports, modules) {
var a = require('a');
a.doSomething();
// 此处省略100行
...
var b = require("b");//按需加载
b.doSomething();
...
})

(2)AMD 的 API 默认是一个当多个用,CMD 的 API 严格区分,推崇职责单一。

对于依赖的模块,AMD是提前执行,CMD是延迟执行。

具体细节可点击参考

4.ES6模块化

ES6在语言的层面上实现了模块化。浏览器厂商和 Node.js 都宣布要原生支持该规范。它将逐渐取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。

在 ES6 中,使用export关键字来导出模块,使用import关键字引用模块。但是浏览器还没有完全兼容,需要使用babel转换成ES5。

// 导出
export function hello() { };
export default {
// ...
};
// 导入
import { readFile } from 'fs';
import React from 'react';

使用import导入模块时,需要知道要加载的变量名或函数名。

在ES6中还提供了export default,为模块指定默认输出.对应导入模块import时,不需要使用大括号。

上面示例中的代码改写成ES6形式:

//math.js
var num = 0;
var add = function (a, b) {
return a + b;
};
export { num, add }; //导入
import { num, add } from './math';
function test(ele) {
ele.textContent = add(1 + num);
}

缺点

浏览器还没有完全兼容,必须通过工具转换成标准的 ES5 后才能正常运行。

5.小结

本文从script引入js文件讲起,到服务器端模块的规范CommonJs,再到推崇依赖前置的浏览器端模块的规范AMD、推崇依赖就近的浏览器端模块的规范CMD,最后介绍了ES6的模块化。每个介绍中都有各规范基本的用法和一个示例。如有问题,欢迎指正。

此文已由作者授权腾讯云+社区发布


一览js模块化:从CommonJS到ES6的更多相关文章

  1. JS模块化规范CommonJS,AMD,CMD

    模块化是软件系统的属性,这个系统被分解为一组高内聚,低耦合的模块.理想状态下我们只需要完成自己部分的核心业务逻辑代码,其他方面的依赖可以通过直接加载被人已经写好模块进行使用即可.一个模块化系统所必须的 ...

  2. JS模块化:CommonJS和AMD(Require.js)

    早期的JS中,是没有模块化的概念的,这一情况直到09年的Node.js横空出世时有了好转,Node.js将JS作为服务端的编程语言,使得JS不得不寻求模块化的解决方案. 模块化概念 在JS中的模块是针 ...

  3. js模块化规范—commonjs

    commonjs规范说明 每个js文件都可当作一个模块 在服务器端: 模块的加载是运行时同步加载的(不会阻塞,等待时间回比较长).在浏览器端: 模块需要提前编译打包处理 commonjs规范基本语法 ...

  4. js模块化编程之CommonJS和AMD/CMD

    js模块化编程commonjs.AMD/CMD与ES6模块规范 一.CommonJS commonjs的require是运行时同步加载,es6的import是静态分析,是在编译时而不是在代码运行时.C ...

  5. webpack学习2.1 模块化开发(JS模块化&CSS模块化)

    一.JS模块化 命名空间,COMMONJS,AMD/CMD/UMD,ES6 module 1.什么是命名空间 库名.类别名.方法名 弊端:在命名空间重复生命,要记住完整的路径名(而且很长) var N ...

  6. 再唠叨JS模块化加载之CommonJS、AMD、CMD、ES6

    Javascript模块化编程,已经成为一个迫切的需求.理想情况下,开发者只需要实现核心的业务逻辑,其他都可以加载别人已经写好的模块. Javascript社区做了很多努力,在现有的运行环境中,实现” ...

  7. js 模块化的一些理解和es6模块化学习

    模块化 1 IIFE 2 commonjs 3 浏览器中js的模块化 4 简单理解模块加载器的原理  5 es6 之前在参加百度前端技术学院做的小题目的时候,自己写模块的时候 都是写成立即调用表达式( ...

  8. 深度扫盲JavaScript的模块化(AMD , CMD , CommonJs 和 ES6)

    原文地址 https://blog.csdn.net/haochangdi123/article/details/80408874 一.commonJS 1.内存情况 对于基本数据类型,属于复制.即会 ...

  9. js模块化AMD、CMD、ES6

    AMD CMD ES6模块化 各个模块化规范对比理解 一.AMD 在上一篇js模块化入门与commonjs解析与应用中详细的解析了关于commonjs模块化规范,commonjs采用的用同步加载方式, ...

随机推荐

  1. 星星打分,今天我们就用Jq代码来实现,看看究竟是如何实现的 其中有两个重要的事件mouseenter和mouseleave效果如下图

    <!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml"><head> <met ...

  2. 使用Eclipse的代码追踪功能

    在使用Java编写复杂一些的程序时,你会不会常常对一层层的继承关系和一次次方法的调用感到迷惘呢?幸亏我们有了Eclipse这么好的IDE可以帮我们理清头绪--这就要使用Eclipse强大的代码追踪功能 ...

  3. opencv2.4.13+python2.7学习笔记--opencv中的Gui特性--图片:读图像,显示图像,保存图像

    阅读对象:可以配置opencv+Python环境的任何人,毕竟写这篇文章的人就是小白. 1.环境说明 1.1opencv版本: 1.2Python版本: 1.3系统:win7 注: (1)opencv ...

  4. 信息安全技能树(SecWiki中Web安全工程师职位建议)

    职位描述: 对公司网站.业务系统进行安全评估测试(黑盒.白盒测试): 对公司各类系统进行安全加固: 对公司安全事件进行响应,清理后门,根据日志分析攻击途径: 安全技术研究,包括安全防范技术,黑客技术等 ...

  5. Android程序backtrace分析方法

    如何分析Android程序的backtrace 最近碰到Android apk crash的问题,单从log很难定位.从tombstone里面得到下面的backtrace. *** *** *** * ...

  6. OC重写init方法

    在创建一个对象的时候我们经常会用到init方法,单单是init只能是初始化,当我们在初始化的时候想要给这个对象加上默认的东西的时候, 系统提供的init方法就不能满足我们的需要,这时,就需要我们自己去 ...

  7. ubuntu自带截图工具--方便好用(转)

    一般用到的截图类型有三种:全屏.当前活动窗口.自定义区域,其中自定义区域截图是最灵活也是我们用的最多的方式.在ubuntu下可以通过其自带的截图工具轻松实现这三种功能. ubuntu自带的截图工具为s ...

  8. tornadoの2

    tornado之日记本——   1.diary.py:   import time from model.database import DataBase from tornado import we ...

  9. Android基础知识学习

    IPC  (Inter-Process Communication) 意思是: 进程间的通信,是指两个进程之间进行数据交换的过程. Android中如何开启多进程呢? 只需要给四大组件(Activit ...

  10. SVN设置全局忽略提交文件或者目录

    在目录中右击选择TortoiseSVN -> 设置 -> 常规设置 -> 全局忽略样式 修改全局忽略样式(可以设置忽略的文件或者目录,以空格隔开):*.o *.lo *.la *.a ...