前端模块化发展历程

本文将从以下三点来做一个详细讲解:

  1. 模块化产生
  2. 早期模块化解决方案
  3. 模块化规范的产生和差异

模块化产生

在早期的前端开发中,并没有模块的概念,模块只在服务端存在,用于处理复杂的业务通信等。 直到 AJAX 被提出,前端能够像后端请求数据,前端逻辑越来越复杂,就出现了许多问题:全局变量,函数名冲突,依赖关系不好处理... 随着业务逻辑的增加,对模块需求越来越大,所以才有了后续一系列 AMD、commonJS、ES6Module 规范。

早期模块化解决方案

两种解决方法:

  • 匿名函数自调用(闭包): 形成私有变量; 栈内存处理 
  • 基于对象进行分组 堆内存处理; “单例模式思想” : 基于单独的实例, 来实现信息分组, 避免全局变量的污染

下面一个简单的例子

// 新闻板块
let newMOdel = (function(){
  let time = new  Date()
  const query = function query() {}
  const handle = function handel() {}
  return {
    query,
    handle
  }
}())
// 皮肤板块
let skinModel = (function() {
  let time = '2021-07-05'
  const hanle = function handel(){ }
  newMOdel.query()
}())

最早期的模块编程思想就是这种 高级单例设计模「闭包+对象」的组合 模块块化编程思想:就是各个板块/模块 /功能 拼接成一起的东西 ,提出公共的模块。

带来的好处?

公用&复用性、提供开发效率、方便管理、团队协作开发 ; 问题:需要自己构建、根据模块间的依赖关系,需要明确导出顺序。 所以就产生了一些其他的模块化规范。

模块化规范 - AMD

AMD 即 Asynchronous Module Definition:异步模块加载,代表 require.js

RequireJS是一个遵守AMD规范的工具库,用于客户端的模块管理。它通过 define 方法,将代码定义为模块;通过 require 方法,实现代码的模块加载,使用时需要下载和导入项

 文件目录

├── AMD  
    ├── moduleA.js  
    ├── moduleB.js  
    ├── main.js  
    └── require.min.js 

简单实现一个require.js

let factories = {}
function define(moduleName,factory) {
  factories[moduleName] = factory
}
function require(modules,callback) {
  modules = modules.map(function(item){
    let factory = factories[item];  // 定义好每一个 然后把它执行
    return factory() // 执行之后返回的东西 放到modules
  });
  callback(...modules) // 然后回掉函数执行这些modules
}
/**使用AMD */
define('moduleA', function() {
  return {
    fn() {
      console.log('moduleA')
    }
  }
  
});
define('moduleB', function() {
  return {
    fn() {
      console.log('moduleB')
    }
  }
  
});
require(['moduleB','moduleA'],function(moduleB,moduleA) {
  moduleB.fn()
  moduleA.fn()
})

模块化规范 - CMD

CMD即 Common Module Definition : 通用模块加载。

CMD(Sea.js )& CommonJs规范(Node.js)。

问题:CommonJs只能在 node 环境下支持,客户端/浏览器不支持  CommonJS 规范

那如何让浏览器支持CommonJs规范? 所以有了 Sea.js  ,也就产生了CMD规范(Sea.js 就是Commonjs规范直接搬到浏览器上 )

AMD、CMD 区别

AMD 是 RequireJS 在推广过程中对模块定义的规范化产出 CMD是SeaJS在推广过程中对模块化定义的规范化产出

区别:

  • 对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。不过 RequireJS 从 2.0 开始,也改成可以延迟执行(根据写法不同,处理方式不同)。CMD 推崇 as lazy as possible.
  • CMD 推崇依赖就近,AMD 推崇依赖前置

模块化规范 - ES6Module

 ModuleA.js

const sum =  function sum(...args){
  let len = args.length
  let firstItem = args[0]
  if(len === 0) return 0;
  if(len === 1) return firstItem;
  return args.reduce((total,item) => {
    return total + item
  })
}

export default { sum }

moduleB.js

import A from './a.js'
const average = function average(...args) {
  let len = args.length
  let firstItem = args[0]
  if(len === 0) return 0;
  if(len === 1) return firstItem;
  return (A.sum(...args) / args.length).toFixed(2)
}

export default  { average }

main.js

import A from './a.js'
import B from './b.js'
console.log(A.sum(1,2,3))
console.log(B.average(1,2,3))

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script type="module" src="./main.js"></script>
</body>
</html>

注意:

  • es6Module 不需要引入外部依赖,浏览器可以直接运行,但要告诉浏览器我是esModule规范,type='module'   <script type="module" src="./main.js"></script>
  • es6Module 浏览器不支持file协议,要在本地起一个服务,可以在vscode上装一个live serve插件,给本地一个服务。

ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案

特点:webpack 支持、浏览器也支持.        

CommonJS、ES6Module差异

  • CommonJs输出的是一个值的拷贝,ES6输出的是值的引用
  • CommonJs是运行时加载,ES Module是编译时就确认了依赖关系

第二个差异是因为 CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。

 

 

posted @ 2021-07-14 17:03  _skylar  阅读(523)  评论(0编辑  收藏  举报