前端模块化详解

模块化开辟轻易代码的治理,进步代码复用性,下降代码耦合,每一个模块都邑有本身的作用域。当前盛行的模块化范例有CommonJS,AMD,CMD,ES6的import/export

  • CommonJS的重要实践者就是nodejs,平常对模块输出用module.exports去输出,用require去引入模块,CommonJS平常采纳同步加载【require / module.exports / exports】
  • AMD顺从RequireJs范例,推重依靠前置(提早实行)【require / defined】
  • CMD顺从SeaJs范例,推重依靠就近(耽误实行)【require / defined】
  • ES6 可静态剖析,提早编译,不是在运转时确认【import / export】

生长进程

简朴封装 -> 定名空间/modules -> script loader/modules loader -> 同步加载CommonJS/AMD/CMD -> ES6 import export/export default -> 模块打包东西browserify/webpack

简朴封装

用法:把差别的函数简朴地放在一同,看做一个模块
瑕玷:

  • “污染”了全局变量,没法保证不与其他模块发作变量名争执;
  • 模块成员之间看不出直接关联

对象(定名空间)

用法:把功用代码放入对象中,看成对象的属性
长处:减少了全局上的变量数量,防止变量全局污染
瑕玷:实质是对象,而这个对象会暴露一切模块成员,内部状况能够被外部改写

立时实行函数(IIFE)

  1. 声明一个匿名函数
  2. 立时挪用这个匿名函数

作用:建立一个自力的作用域。数据是私有的, 外部只能经由过程暴露的要领操纵
这个作用域内里的变量,表面接见不到(即防止「变量污染」)

CommonJS

导入导出:require & exports/module.exports
重要实践者:NodeJS

模块导入
语法:require(module)

eg:
var math = require('math');
math.add(2, 3);

假如模块输出的是一个函数,那就不能定义在exports对象上面,而要定义在module.exports变量上面。

// example2.js
module.exports = function () {
    console.log("hello world")
}
        
// main.js 
require('./example2.js')()

AMD(Asynchronous Module Definition)

首倡依靠前置,在定义模块的时刻就要声明其依靠的模块。在requireJs推行过程当中发生的范例

模块定义
define(id?, dependencies?, factory)
id:字符串,模块称号(可选)
dependencies:数组,是我们要载入的依靠模块(可选),运用相对途径
factory:工场要领,返回一个模块函数

模块导入
require([module], callback)
module:是一个数组,内里的成员就是要加载的模块
callback:则是加载胜利今后的回调函数

requireJS 长处

  • 完成js文件的异步加载,防止网页落空相应;
  • 治理模块之间的依靠性,根据依靠关联加载,便于代码的编写和保护。

采纳异步体式格局加载模块,经由过程define来定义一个模块,经由过程require来引入模块,模块的加载不影响背面语句的实行,一切依靠于这些模块的语句都写在一个回调函数中,加载终了后,这个回调函数才运转

CMD(Common Module Definition)

首倡就近依靠(按需加载),在用到某个模块的时刻再去require进来。在Sea.js推行过程当中发生的范例

模块定义
define(id?, dependencies?, factory) 与AMD相似

// eg
define('hello', ['jquery'], function(require, exports, module) {
   // 模块代码
   // return 模块对象
});

模块导入导出
与 AMD 相似

ES6

导入导出:import/export/export default

export defalut

默许输出是一个函数/变量
其他模块加载该模块时,import敕令能够为该匿名函数指定恣意名字
须要注重的是,这时候import敕令背面,不运用大括号

// export-fn.js 
export default function () {
    console.log('foo');
}

import foo from 'export-fn.js'

export default敕令也能够用在非匿名函数前,视同匿名函数加载

export default 敕令用于指定模块的默许输出。一个模块只能有一个默许输出,因而export default 敕令只能运用一次。所以,import敕令背面才不必加大括号,由于只能够唯一对应export default敕令。
实质上,export default就是输出一个叫做default的变量或要领,然后体系许可你为它取恣意名字

export & export default区分

运用export default时,对应的import语句不须要运用大括号,默许输出
运用export时,对应的import语句须要运用大括号

// 第一组 export default
export default function crc32() { // 输出
    // ...
}
import crc32 from 'crc32'; // 输入


// 第二组 export 
export function crc32() { // 输出
    // ...
};
import {crc32} from 'crc32'; // 输入

ES6、AMD和CommonJS区分

ES6模块使得编译时就可以肯定模块的依靠关联,以及输入和输出的变量。
CommonJS 和 AMD 模块,都只能在运转时肯定这些东西;
CommonJS 模块就是对象,输入时必需查找对象属性

  • CommonJS模块

     let { stat, exists, readFile } = require('fs')

    团体加载fs模块(即加载fs的一切要领),天生一个对象(_fs),然后再从这个对象上面读取 3 个要领。这类加载称为“运转时加载”

  • ES6模块

    import { stat, exists, readFile } from 'fs'

    从fs模块加载 3 个要领,其他要领不加载,这类加载称为“编译时加载”或许静态加载

  • CommonJS模块

    const path = './' + fileName
    const myModual = require(path)

    动态加载,require究竟加载哪个模块,只要运转时才晓得

import()

动态加载,正在提案阶段,import()返回一个 Promise 对象
import()加载模块胜利今后,这个模块会作为一个对象,看成then要领的参数
import()相似于 Node 的require要领,区分重如果前者是异步加载,后者是同步加载。

实用场景
(1)按需加载
(2)前提加载
(3)动态的模块途径

注:关于ES6模块化,细致见 阮一峰的es6入门 module模块

es6 与 commonJS/AMD 模块化区分

  • 模块化的范例:CommonJS和AMD两种。前者用于服务器,后者用于浏览器。
  • 而ES6 中供应了简朴的模块体系,完全能够庖代现有的CommonJS和AMD范例,成为浏览器和服务器通用的模块解决方案。
  • ES6 模块的设想头脑,是只管的静态化,使得编译时就可以肯定模块的依靠关联,以及输入和输出的变量。CommonJS 和 AMD 模块,都只能在运转时肯定这些东西。

require与import的区分(commonJS与ES6模块化区分)

require/exports是CommonJS的一部分;import/export是ES6的新范例
require支撑 动态导入,import不支撑,正在提案 (babel 下可支撑)
require是 同步 导入,import属于 异步 导入
require是 值拷贝,导出值变化不会影响导入值;import是值援用,指向 内存地址,导入值会随导出值而变化

参考:
前端工程师必备:前端的模块化
阮一峰的es6入门 module模块

    原文作者:adaxxl
    原文地址: https://segmentfault.com/a/1190000019015341
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞