js模块化发展历程

2019年04月15日Web前端0

js作为一个非主流语言发展到现在如此热门的语言,一定经历了很多的变迁,我们从模块化方面来了解下js的发展。

直接定义

这时候的前端也没有模块化的概念,当然js文件之间也没有太多的束缚,只是简单的堆砌script标签,没有全局变量与局部变量的概念,定义的变量都是全局的。因此很容易出现,b文件改了a文件中的变量内容,却不知道,照成后期开发难,维护难的问题,甚至加个变量名都得全局搜索下。

渐有模块

也许是意识到模块化的问题后,开始逐渐减少全局变量,并增加单个js的内聚性。

减少全局变量

开始减少全局暴露的js变量,

var glo = {
    name: '',
    age: 123
};

增加局部变量

jquery的源码就非常典型,利用自执行函数,减少变量的暴露,

(function() {
    // ....
    window.what = what;
})();

私有变量模拟

我们都知道js是没有私有变量的概念的,但是可以模拟出来:

var A = function() {
    var _a = 0;
    
    this.add = function() {
        _a++;
    }
    this.getA = function() {
        return _a;
    }
}
var aaa = new A();
aaa.getA();
aaa.add();
aaa.add();
aaa.getA();

利用function的作用域,完美的模拟了私有变量。 我们开始意识到前端模块化的重要性,当然这是好事。

蓬勃发展

依赖注入

用过angular的都知道,借鉴java的概念,angular中模块化很重要的一块。

commonjs

随着nodejs的出现,js走向了服务端,可是作为服务端的语言没有模块化的设计,那一定是非常混乱的。于是commonjs规范就脱颖而出了。

// a.js
module.export = {};

在入口文件app.js中,

// app.js
var a = require('./a.js');

那么前端是否能照搬这一套呢?其实是不行的,因为require是同步加载的,正常清空下后端要加载的文件都是在服务器上的,访问都是非常快的。而前端的资源都是通过网络加载的,不确定性和延迟都比较高,所以,这套规范不适用于前端。

requirejs

RequireJS 是一个JavaScript模块加载器,是AMD规范最好的实现者之一。

require(['moduleA', 'moduleB', 'moduleC'], function (moduleA, moduleB, moduleC){
    // ...
});

requireJS会异步加载这三个模块,等都加载完成后,触发对应的回调事件。

seajs

SeaJS是一个遵循CMD规范的JavaScript模块加载框架,可以实现JavaScript的模块化开发及加载机制。

amd与cmd和commonjs详细内容可以查看这篇文章,AMD、CMD和CommonJS规范

UMD

兼容了 CommonJS 与 Amd,其核心思想是,如果在 commonjs 环境(存在 module.exports,不存在 define),将函数执行结果交给 module.exports 实现 Commonjs,否则用 Amd 环境的 define,实现 Amd。结构如下:

(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(['b'], factory);
    } else if (typeof module === 'object' && module.exports) {
        // Node. Does not work with strict CommonJS, but
        // only CommonJS-like environments that support module.exports,
        // like Node.
        module.exports = factory(require('b'));
    } else {
        // Browser globals (root is window)
        root.returnExports = factory(root.b);
    }
}(this, function (b) {
    //use b in some fashion.

    // Just return a value to define the module export.
    // This example returns an object, but the module
    // can return a function as the exported value.
    return {};
}));

标准化

模块化终于在es6中形成了标准,export和import方式也逐步被我们使用。

工具

在我们常用的打包工具webpack中,是可以选择默认的打包方式的,支持commonjs和requirejs,umd方式也是支持的。