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

前言

不论是前端老司机仍是刚接触前端的"菜鸟"。模块化想必在天天工做中,或多或少都会接触到。尤为针对一些针对ReactVue开发的同窗来讲,那就是天天都会脱口而出的一个必备术语。而且在不少技术文档中,都经常看到AMDUMDCOMMONJS还有ES6中的modulejavascript

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

今天咱们就来唠唠这段不为人知的故事。前端

模块化本质

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

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

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

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

对象字面量

因为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是在ES6module没出现以前,经常使用的前端模块解决方案。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的用法

各个模块比较

模块化方案 加载 同步/异步 浏览器 服务端 模块定义 模块引入
Module Pattern 取决于代码 取决于代码 支持 支持 IIFE 命名空间
AMD 提早预加载 异步 支持 构建工具r.js define require
Common 值拷贝,运行时加载 同步 原生不支持 须要使用browserify提早打包编译 module.exports require
ES Modules(ES6) 实时绑定,动态绑定,编译时输出 同步 支持 需用babel转译 export import

本文参考连接:

  1. requirejs.org/docs/api.ht…
  2. addyosmani.com/resources/e…
  3. es6.ruanyifeng.com/#docs/modul…
  4. www.commonjs.org/
  5. www.cnblogs.com/scq000/p/10…
相关文章
相关标签/搜索