分享

JavaScript模块化,让你了解JavaScript

 止观观止 2019-07-13

什么是JavaScript模块化?

模块化在我看来,就是把一些公共的函数封装起来给其他地方调用,而不用重复去写一些冗余的函数代码。

JavaScript模块化大致发展过程

CommonJS(服务端) => AMD (浏览器端) => CMD / UMD => ES Module

CommonJS

CommonJS主要用于服务器端。 这个规范是同步的

特点:

  • 模块可以多次加载,首次加载的结果将会被缓存,想让模块重新运行需要清除缓存。
  • 模块的加载是一项阻塞操作,也就是同步加载。
// a.js module.exports = { moduleFunc: function() { return true; }; } // 或 exports.moduleFunc = function() { return true; }; // 在 b.js 中引用 var moduleA = require('a.js'); // 或 var moduleFunc = require('a.js').moduleFunc; console.log(moduleA.moduleFunc()); console.log(moduleFunc())

AMD规范

在commonJS中, 模块的加载过程是一个同步的过程, 很明显地,如果在浏览器端, 肯定就会引起浏览器页面的阻塞,因此,这时候对模块异步加载的需求就出现了。从而出现AMD规范

异步模块定义规范(AMD)制定了定义模块的规则,这样模块和模块的依赖可以被异步加载。这和浏览器的异步加载模块的环境刚好适应(浏览器同步加载模块会导致性能、可用性、调试和跨域访问等问题)

这时候RequireJS应运而生

RequireJS

特点:

  • 前置依赖,异步加载
  • 便于管理模块之间的依赖性,有利于代码的编写和维护。
 // a.js define(function (require, exports, module) { console.log('a.js'); exports.name = 'Jack'; }); // b.js define(function (require, exports, module) { console.log('b.js'); exports.desc = 'Hello World'; }); // main.js require(['a', 'b'], function (moduleA, moduleB) { console.log('main.js'); console.log(moduleA.name + ', ' + moduleB.desc); }); // 执行顺序: // a.js // b.js // main.js

然而, 他也有他的不足之处

按照 AMD 的规范,在定义模块的时候需要把所有依赖模块都罗列一遍(前置依赖),而且在使用时还需要在 factory 中作为形参传进去。

define(['a', 'b', 'c', 'd', 'e', 'f', 'g'], function(a, b, c, d, e, f, g){ ..... });

是不是看起来又丑又复杂。。

RequireJS 模块化的顺序是这样的:模块预加载 => 全部模块预执行 => 主逻辑中调用模块,所以实质是依赖加载完成后还会预先一一将模块执行一遍,这种方式会使得程序效率有点低。

这个时候就出现了CMD规范,典型的就是seajs模块化

SeaJS

SeaJS 模块化的顺序是这样的:模块预加载 => 主逻辑调用模块前才执行模块中的代码,通过依赖的延迟执行,很好解决了 RequireJS 被诟病的缺点。

 // a.js define(function (require, exports, module) { console.log('a.js'); exports.name = 'Jack'; }); // main.js define(function (require, exports, module) { console.log('main.js'); var moduleA = require('a'); console.log(moduleA.name); }); // 执行顺序 // main.js // a.js

ES6的module

ES Module 的思想是尽量的静态化,即在编译时就确定所有模块的依赖关系,以及输入和输出的变量,和 CommonJS 和 AMD/CMD 这些标准不同的是,它们都是在运行时才能确定需要依赖哪一些模块并且执行它。ES Module 使得静态分析成为可能

  • 模块功能主要由两个命令构成:export 和 import。export 命令用于规定模块的对外接口,import 命令用于输入其他模块提供的功能。
  • 通过 export 命令定义了模块的对外接口,其他 JS 文件就可以通过 import 命令加载这个模块。
模块的定义 /** * export 只支持对象形式导出,不支持值的导出,export default 命令用于指定模块的默认输出, * 只支持值导出,但是只能指定一个,本质上它就是输出一个叫做default 的变量或方法 */ // 写法 1 export var m = 1; // 写法 2 var m = 1; export { m }; // 写法 3 var n = 1; export { n as m }; // 写法 4 var n = 1; export default n; 模块的引入 // 解构引入 import { firstName, lastName, year } from 'a-module'; // 为输入的变量重新命名 import { lastName as surname } from 'a-module'; // 引出模块对象(引入所有) import * as ModuleA from 'a-module';

在使用 ES Module 值得注意的是:import 和 export 命令只能在模块的顶层,在代码块中将会报错

这是因为 ES Module 需要在编译时期进行模块静态优化,import 和 export 命令会被 JavaScript 引擎静态分析,先于模块内的其他语句执行,这种设计有利于编译器提高效率,但也导致无法在运行时加载模块(动态加载)。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多