前端模块化的理解

83 阅读4分钟

模块的定义:

可以理解成实现特定功能的相互独立的一组方法

为什么要使用模块化:

  • 可维护性
  • 命名空间
  • 可复用性

模块化规范

  • CommonJS
  • Module(es6)
  • AMD
  • UMD
  • CMD

common.js 和 es6 中模块引入的区别?

CommonJS 是一种模块规范,最初被应用于 Nodejs,成为 Nodejs 的模块规范。

运行在浏览器端的 JavaScript 由于也缺少类似的规范,在 ES6 出来之前,前端也实现了一套相同的模块规范 (例如: AMD),用来对前端模块进行管理。

自 ES6 起,引入了一套新的 ES6 Module 规范,在语言标准的层面上实现了模块功能,而且实现得相当简单,有望成为浏览器和服务器通用的模块解决方案。

但目前浏览器对 ES6 Module 兼容还不太好,我们平时在 Webpack 中使用的 export 和 import,会经过 Babel 转换为 CommonJS 规范。

在使用上的差别主要有:

1、CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。

2、CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。

3、CommonJs 是单个值导出,ES6 Module可以导出多个

4、CommonJs 是动态语法可以写在判断里,ES6 Module 静态语法只能写在顶层

5、CommonJs 的 this 是当前模块,ES6 Module的 this 是 undefined

CommonJS

CommonJS 是一套 Javascript 模块规范,用于服务端

CommonJS 扩展了JavaScript声明模块的API,

通过CommonJS,每个JS文件独立地存储它模块的内容(就像一个被括起来的闭包一样)。在这种作用域中,我们通过 module.exports 语句来导出对象为模块,再通过 require 语句来引入

  • 所有代码都运行在模块作用域,不会污染全局作用域
  • 模块是同步加载的,即只有加载完成,才能执行后面的操作
  • 模块在首次执行后就会缓存,再次加载只返回缓存结果,如果想要再次执行,可清除缓存
  • require返回的值是被输出的值的拷贝,模块内部的变化也不会影响这个值

如:

function myModule() {
  this.hello = function() {
    return 'hello!';
  }
}
module.exports = myModule;

// 然后再通过require去加载

ES Module

原生JS(es6)解决方案, ES6设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量

模块功能主要由两个命令构成:

export:用于规定模块的对外接口
import:用于输入其他模块提供的功能

如:

export default myModule
import myModule from './myModule'

动态加载

允许您仅在需要时动态加载模块,而不必预先加载所有模块,这存在明显的性能优势

这个新功能允许您将import()作为函数调用,将其作为参数传递给模块的路径。它返回一个 promise,它用一个模块对象来实现,让你可以访问该对象的导出

import('/modules/myModule.mjs')
  .then((module) => {
    // Do something with the module.
  });

复合写法

如果在一个模块之中,先输入后输出同一个模块,import语句可以与export语句写在一起

export { foo, bar } from 'my_module';

// 可以简单理解为
import { foo, bar } from 'my_module';
export { foo, bar };

同理能够搭配as、*搭配使用

AMD (Asynchronous Module Definition)

提倡依赖前置,在定义模块的时候就要声明其依赖的模块

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

代表库为require.js

如:

/** main.js 入口文件/主模块 **/
// 首先用config()指定各模块路径和引用名
require.config({
  baseUrl: "js/lib",
  paths: {
    "jquery": "jquery.min",  //实际路径为js/lib/jquery.min.js
    "underscore": "underscore.min",
  }
});
// 执行基本操作
require(["jquery","underscore"],function($,_){
  // some code here
});

CMD (Common Module Definition)

CMD规范是国内SeaJS的推广过程中产生的
提倡就近依赖(按需加载),在用到某个模块的时候再去require

define(function (require, exports, module) {
  var one = require('./one')
  one.do()
// 就近依赖,按需加载
  var  two = require('./two')
  two.do() 
})

UMD (Universal Module Definition)

AMD和CommonJS的结合,跨平台的解决方案,UMD先判断是否支持Node.js的模块(exports)是否存在,存在则使用Node.js模块模式。在判断是否支持AMD(define是否存在),存在则使用AMD方式加载模块

(function (window, factory) {
    if (typeof exports === 'object') {
        module.exports = factory();
    } else if (typeof define === 'function' && define.amd) {
        define(factory);
    } else {
        window.eventUtil = factory();
    }
})(this, function () {
    //module ...
});