资讯专栏INFORMATION COLUMN

一览js模块化:从CommonJS到ES6

antz / 1629人阅读

摘要:模块化规范有的模块系统。规范是服务器端模块的规范,由推广使用。对于依赖的模块,是提前执行,是延迟执行。浏览器厂商和都宣布要原生支持该规范。它将逐渐取代和规范,成为浏览器和服务器通用的模块解决方案。

本文由云+社区发表

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

模块化开发的优点

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

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

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

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



缺点:

(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的模块化。每个介绍中都有各规范基本的用法和一个示例。如有问题,欢迎指正。

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/100347.html

相关文章

  • 【Step-By-Step】高频面试题深入解析 / 周刊07

    摘要:复杂数据类型变量,赋值给之后,只读引用与关联,和中存储的是同一个对象的堆内存地址,当这个对象的值发生改变时,此时的值也会发生变化。 不积跬步无以至千里。 关于【Step-By-Step】 Step-By-Step (点击进入项目) 是我于 2019-05-20 开始的一个项目,每个工作日发布一道面试题。每个周末我会仔细阅读大家的答案,整理最一份较优答案出来,因本人水平有限,有误的地方...

    superw 评论0 收藏0
  • Vuex? 和 TypeScript 的 Webpack4.+ 尝鲜

    摘要:静态类型系统能帮助你有效防止许多潜在的运行时错误,而且随着你的应用日渐丰满会更加显著。选择,会生成符合规范的文件,使用,会生成满足规范的文件,使用会生成使用的的代码。使用或者是会生产包含特性的代码。 showImg(https://segmentfault.com/img/bVbbhsr?w=800&h=800); 静态类型系统能帮助你有效防止许多潜在的运行时错误,而且随着你的应用日渐...

    Astrian 评论0 收藏0
  • js中的块化——commonjs,AMD,CMD,UMD,ES6

    摘要:若不存在则模块标识应该默认定义为在加载器中被请求脚本的标识。这也是目前很多插件头部的写法,就是用来兼容各种不同模块化的写法。语句输出的值是动态绑定的,绑定其所在的模块。 前言 历史上,js没有模块化的概念,不能把一个大工程分解成很多小模块。这对于多人开发大型,复杂的项目形成了巨大的障碍,明显降低了开发效率,java,Python有import,甚至连css都有@import,但是令人费...

    qpal 评论0 收藏0
  • 前端块化规范笔记

    摘要:目前通行的的模板规范共有两种和的模块系统,是参照规范实现的即为服务器端模块的规范。规范则是非同步加载模块,允许指定回调函数。 目前通行的Javascript的模板规范共有两种:CommonJS 和 AMD commonjs nodejs的模块系统,是参照commonjs规范实现的 commonjs即为服务器端模块的规范。 commonjs的规范: 根据commonjs规范,一个单独的...

    honmaple 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<