骚年,你对前端模块化了解多少

不管是前端老司机还是刚接触前端的"菜鸟"。 模块化 想必在每天工作中,或多或少都会接触到。尤其针对一些针对 ReactVue 开发的同学来说,那就是每天都会脱口而出的一个必备术语。并且在很多技术文档中,都常常看到 AMDUMDCOMMONJS 还有ES6中的 module

但是,模块化的本质是什么!前端是如何从"茹毛饮血"的 <script> 到现在es6的 module 的呢。

今天我们就来唠唠这段鲜为人知的故事。

模块化本质

何为模块化。其实就是功能的单一化或者说功能的切片化编程。更直白一点就是,每一个独立的功能都有自己独立的 作用域

让我们看看针对模块的英文定义

Modules are an integral piece of any robust application's architecture and typically help in keeping the units of code for a project both cleanly separated and organized.

而JS在实现模块代码有如下方式:

  1. 对象字面量
  2. 设计模式中的模块模式
  3. AMD
  4. CommonJS
  5. ES6 module

让我们针对每一个方式来一一说明

对象字面量

由于JS语法本身没有 块级作用域 的概念(es6之前),所以是没法直接利用 {} 来将指定的代码进行封装。如果想将特定用于处理类似功能的代码合并到一起。对象字面量不失为一个很好的方式。(有人会说,用函数封装也可以啊,记住 JS中一切皆对象 )

Talk is cheap ,show you the code

var myModule = {
 
  myProperty: "北宸",
 
  // 对象字面量可以包含属性和方法
  // 我们还可以为该模块定义配置信息:
  myConfig: {
    useCaching: true,
    language: "en"
  },
 
  // 
  saySomething: function () {
    console.log( "你好啊,世界" );
  },
 
  // 基于配置信息输出一些信息
  reportMyConfig: function () {
    console.log( "缓存: " + ( this.myConfig.useCaching ? "可用" : "禁用") );
  },
 
  // 重新配置信息
  updateMyConfig: function( newConfig ) {
 
    if ( typeof newConfig === "object" ) {
      this.myConfig = newConfig;
      console.log( this.myConfig.language );
    }
  }
};
 
// 你好啊,世界
myModule.saySomething();
 
//  缓存可用
myModule.reportMyConfig();
 
//  fr
myModule.updateMyConfig({
  language: "fr",
  useCaching: false
});
 
//  缓存禁用
myModule.reportMyConfig();

复制代码

从上述代码中,可以看到,将一些操作和数据进行了封装。实现了, 功能切片化 处理。但是如果细想,感觉利用字面量来封装数据和方法,感觉有点 鸡肋 。因为这个对象是一个 单例 。如果只是在一个地方使用和操作,那完全没有问题,但是如果是多个地方都用到呢,同时多个地方都需要对指定的属性进行修改。这就是 牵一发而动全身 的操作。

同时,我们可以看到利用字面量进行数据和方法封装。这些属性都是对外 友好 的。都是能在外部访问到的。没有丝毫的 隐私 ,用传统OOP编程术语来讲。这些属性都是 public 的。也就是说,无法实现属性 私有化

模块模式

为了解决字面量无法进行属性 私有化 。模块模式应用而生。这也是JS语言在早起比较常用的模块化处理方式。

Talk is cheap ,show you the code

var MODULE = (function () {
	var my = {},
		privateVariable = 1;

	function privateMethod() {
		// ...
	}

	my.moduleProperty = 1;
	my.moduleMethod = function () {
		// ...
	};

	return my;
}());
复制代码

从代码上看到,一个 IIFE 赫然映入眼帘。偷偷的告诉大家, 模块模式 就是利用 IIFE 实现的。

为了不占用很大篇幅来讲解这个实现。特定为大家准备了饭后甜点。 JS_Module模式深入了解一下

AMD

其实AMD(Asynchronous Module Definition)是一种为 浏览器 环境书写模块的模式。 而能够实现 异步加载 的关键就在于 RequireJS

RequireJS 是在ES6 module 没出现之前,常用的前端模块解决方案。 RequireJS 将加载的每一个独立模块作为 <script> ,并利用 head.appendChild() 追加到文档中。

RequireJS等待所有依赖模块加载,将该模块需要的额外模块进行排序,并在依赖模块加载完之后,调用本模块的定义函数。

Talk is cheap,show you the code

在项目中存在如下结构,我们用 cart.jsinventory.js 来构建一个 shirt.js

  • my/cart.js
  • my/inventory.js
  • my/shirt.js
define(["./cart", "./inventory"], function(cart, inventory) {
        //返回一个对象用于定义"my/shirt"模块
        return {
            color: "blue",
            size: "large",
            addToCart: function() {
                inventory.decrement(this);
                cart.add(this);
            }
        }
    }
);

复制代码

当然,上述中的本地模块 cart.js 也可以换成 JQuery 等现成的模块。

如果想对 AMD 有一个更深的了解,或者想知道如何定义一个 AMD 模块。可以先移步 RequireJS 官网。

CommonJS

JS有一条定律: Atwood's Law

any application that can be written in JavaScript, will eventually be written in JavaScript.

JS是可以在服务端存在,所以出现了 CommonJS (A Module Format Optimized For The Server),使得JS不仅仅在浏览器端应用,而且在服务端开始 发光发热

CommonJS 是专注于

  1. 服务端应用
  2. 公共工具方法
  3. 基于GUI的桌面程序
  4. 混合应用 (Titanium, Adobe AIR)

AMD 不是一个服务层面。

Talk is cheap ,show you the code

a.js

var x = 5;
var addX = function (value) {
  return value + x;
};
module.exports.x = x;
module.exports.addX = addX;
复制代码

上面代码通过module.exports输出变量x和函数addX。

b.js

var example = require('./a.js');
 
console.log(example.x); // 5
console.log(example.addX(1)); // 6
复制代码

commonJS模块特点

  1. 每个文件就是一个模块,它有自己的作用域(不会污染全局作用域)。在文件里面定义的变量、函数、类,都是这个模块的 私有 的,对外不可见。
  2. 模块加载顺序,按照代码执行顺序。也就是说,是 同步加载 的。
  3. 模块可以重复加载,但是会在加载第一次的时候,就将该模块缓存起来,后面再次加载将从缓存中获取该模块。(注意:如果要重新加载模块,需要清空缓存)

ES6 module

在ES6中,从语法层面就提供了 模块化 的功能。然而受限于浏览器的实现程度,如果想要在浏览器中运行,还是需要通过Babel等转译工具进行编译。

person-module.js

var firstName = '北宸';
var lastName = '范';
export { firstName, lastName };
复制代码

test-module.js

import {firstName,lastName} from './person-module.js';
console.log(`${lastName}${firstName}`)//范北宸
复制代码

具体细节请参考 Module的用法

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章