Bootstrap

前端工程化-模块化机制

前言:

模块化是一种处理复杂系统分解成为更好的可管理模块的方式,它可以把系统代码划分为一系列职责单一,高度解耦且可替换的模块,系统中某一部分的变化将如何影响其它部分就会变得显而易见,系统的可维护性更加简单易得。

前端开发领域(JavaScript、CSS、Template)并没有为开发者们提供以一种简洁、有条理地的方式来管理模块的方法。CommonJS(致力于设计、规划并标准化 JavaScript API)的诞生开启了“ JavaScript 模块化的时代”。CommonJS 的模块提案为在服务器端的 JavaScript 模块化做出了很大的贡献,但是在浏览器下的 JavaScript 模块应用很有限。随之而来又诞生了其它前端领域的模块化方案,像 requireJS、SeaJS 等,然而这些模块化方案并不是十分适用 ,并没有从根本上解决模块化的问题。

模块化的理解:

前端模块化并不等于 JavaScript 模块化,JavaScript 模块化并不等于异步模块化。

模块的含义:
  • 将一个复杂的程序依据一定的规则(规范)封装成几个块(文件), 并进行组合在一起。
  • 块的内部数据与实现是私有的, 只是向外部暴露一些接口(方法)与外部其它模块通信。

模块化的进化过程:
  • 全局function模式 : 将不同的功能封装成不同的全局函数
    处理:将不同的功能封装成不同的全局函数;
    作用:以方法形式封装分离功能;
    弊端:污染全局命名空间, 容易引起命名冲突或数据不安全,而且模块成员之间看不出直接关系;
function fn1(){
   
  ...
}
function fn2(){
   
  ...
}

  • namespace模式 : 简单对象封装
    处理:以对象方式封装相应功能模块;
    作用:减少了全局变量,解决命名冲突;
    弊端:数据不安全,暴露所有模块成员,内部状态可以被外部改写;
let module= {
   
  data: 'natsu',
  foo() {
   
    console.log(this.data);
  }
}
module.data = 'cc' //能直接修改模块内部的数据
module.foo() // cc

  • IIFE模式:匿名函数自调用(闭包)
    处理:将数据和行为封装到一个函数内部, 通过给window添加属性来向外暴露接口;
    作用:数据是私有的, 外部只能通过暴露的方法操作;
    弊端:模块依赖问题。
// index.html文件
<script type="text/javascript" src="module.js"></script>
<script type="text/javascript">
    module.foo()	//natsu
    console.log(module.data) //undefined 不能访问模块内部数据
    module.data = 'cc' //不是修改的模块内部的data
    module.foo() //natsu 没有改变
</script>
// module.js文件
(function(window) {
   
  let data = 'natsu'
  //操作数据的函数
  function foo() {
   
    //用于暴露有函数
    console.log(data)
  }
  //暴露行为
  window.module= {
    foo } //ES6写法
})(window)

  • IIFE模式增强 : 引入依赖
    作用:保证模块的独立性,使得模块之间的依赖关系变得明显。
// index.html文件
  <!-- 引入的js必须有一定顺序(保证依赖关系) -->
  <script type="text/javascript" src="jquery.js"></script>
  <script type="text/javascript" src="module.js"></script>
  <script type="text/javascript">
    module.foo()	//natsu
  </script>
// module.js文件
(function(window, $) {
   
  let data = 'natsu'
  //操作数据的函数
  function foo() {
   
    //用于暴露有函数
    console.log(data)
    $('body').css('background', 'red')
  }
  //暴露行为
  window.module= {
    foo }
})(window, jQuery)

模块化的好处:
  • 避免命名冲突(减少命名空间污染)
  • 更好的功能代码分离, 按需加载
  • 更高复用性
  • 高可维护性

模块化的弊端:
  • <script>引入导致请求过多
  • 依赖关系模糊
  • 难以维护

把所有需要加载的模块按顺序一一加载完毕,当模块很多、依赖关系复杂的情况下会严重影响页面性能,因此我们模块化也需要一定的规范进行约定。

模块化规范:

CommonJS:

概述:

Node 应用由模块组成,采用 CommonJS 模块规范。每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。在服务器端,模块的加载是运行时同步加载的;在浏览器端,模块需要提前编译打包处理。

特点:

  • 所有代码都运行在模块作用域,不会污染全局作用域。
  • 模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要让模块再次运行,就需要清除缓存。
  • 模块加载的顺序,按照其在代码中出现的顺序。

基本语法:

  • 暴露模块:module.exports = value或exports.xxx = value。
  • 引入模块&
;