前端常用4种模块化方案总结

栏目: JavaScript · 发布时间: 5年前

内容简介:JS诞生之初面向简单页面开发, 没有模块的概念。后来页面逐渐复杂, 人类构造到 IIFE 立即执行函数来模拟 模块;之前也有雅虎的实践,使用命名空间 作为模块名。最后衍生出 面向各种使用场景 的 JS 模块标准。例如:面向浏览器的 AMD面向Nodejs的 CommonJS

JS诞生之初面向简单页面开发, 没有模块的概念。后来页面逐渐复杂, 人类构造到 IIFE 立即执行函数来模拟 模块;之前也有雅虎的实践,使用命名空间 作为模块名。最后衍生出 面向各种使用场景 的 JS 模块标准。例如:

面向浏览器的 AMD

面向Nodejs的 CommonJS

对于这种分裂状态ES标准也在尽力弥合。 但是目前流行的实践是 UMD模式。

1 AMD

AMD 是requirejs 推广产出的规范,主要用于浏览器环境,通过define和require这两个定义模块、调用模块。

定义模块

define("alpha", ["require", "exports", "beta"], function (require, exports, beta) {
       exports.verb = function() {
           return beta.verb();
           //Or:
           return require("beta").verb();
       }
   });
//  返回对象的匿名模块
 define(["alpha"], function (alpha) {
       return {
         verb: function(){
           return alpha.verb() + 2;
         }
       };
   });

调用模块

require(['foo', 'bar'], function ( foo, bar ) {
        foo.doSomething();
});

define(function (require) {
        require(['a', 'b'], function (a, b) {
            //modules a and b are now available for use.
        });
    });

2 commonJS

Node 应用由模块组成,采用 CommonJS 模块规范。

每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。

CommonJS 加载模块是同步的,所以只有加载完成才能执行后面的操作。像Node.js主要用于服务器的编程,加载的模块文件一般都已经存在本地硬盘,所以加载起来比较快,不用考虑异步加载的方式,所以CommonJS规范比较适用。但如果是浏览器环境,要从服务器加载模块,这是就必须采用异步模式。所以就有了 AMD CMD 解决方案。

// a.js
// 相当于这里还有一行:var exports = module.exports;代码
exports.a = 'Hello world'; // 相当于:module.exports.a = 'Hello world';

// b.js
var moduleA = require('./a.js');
console.log(moduleA.a); // 打印出hello world

3 UMD

兼容 AMD 和 commonjs,也兼容 全局变量定义的 通用的模块化规范

(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD
        define(['jquery'], factory);
    } else if (typeof exports === 'object') {
        // Node, CommonJS-like
        module.exports = factory(require('jquery'));
    } else {
        // Browser globals (root is window)
        root.returnExports = factory(root.jQuery);
    }
}(this, function ($) {
     function a(){}; // 私有方法,因为它没被返回 (见下面)
    function b(){}; // 公共方法,因为被返回了
    function c(){}; // 公共方法,因为被返回了
    // 暴露公共方法
    return {
        b: b,
        c: c
    }
}));

4 ES6 Module

ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,旨在成为浏览器和服务器通用的模块解决方案。其模块功能主要由两个命令构成:export和import。

export命令用于规定模块的对外接口,导出模块暴露的api ;import命令用于输入其他模块提供的功能,引入其他模块。

/** 定义模块 math.js **/
var basicNum = 0;
var add = function (a, b) {
    return a + b;
};
export { basicNum, add };

/** 引用模块 **/
import { basicNum, add } from './math';
function test(ele) {
    ele.textContent = add(99 + basicNum);
}

5 ES6 模块与 CommonJS 模块的差异

  1. CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
  • CommonJS 模块输出的是值的拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。
  • ES6 模块的运行机制与 CommonJS 不一样。JS 引擎对脚本静态分析的时候,遇到模块加载命令import,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。换句话说,ES6 的import有点像 Unix 系统的“符号连接”,原始值变了,import加载的值也会跟着变。因此,ES6 模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。
  1. CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
  • 运行时加载: CommonJS 模块就是对象;即在输入时是先加载整个模块,生成一个对象,然后再从这个对象上面读取方法,这种加载称为“运行时加载”。
  • 编译时加载: ES6 模块不是对象,而是通过 export 命令显式指定输出的代码,import时采用静态命令的形式。即在import时可以指定加载某个输出值,而不是加载整个模块,这种加载称为“编译时加载”。

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


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Effective JavaScript

Effective JavaScript

David Herman / Addison-Wesley Professional / 2012-12-6 / USD 39.99

"It's uncommon to have a programming language wonk who can speak in such comfortable and friendly language as David does. His walk through the syntax and semantics of JavaScript is both charming and h......一起来看看 《Effective JavaScript》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具