前端模块化

作者: 淘淘笙悦 | 来源:发表于2017-10-08 12:16 被阅读119次

    一开始,javascript 的出现只是作为简单脚本语言来实现简单的页面逻辑,而随着互联网的发展和 web 2.0 时代的到来,越来越多的交互逻辑被放到了客户端实现,这就使得我们的 js 脚本文件变得越来越复杂,这时候需要有一种‘模块化’的思想来组织我们的 js 代码。
    javascript 并不是一种模块化语言,它不支持‘类’和‘模块’,尽管在 es6 中已经有了‘类’和‘模块’的概念,但要等到各大浏览器都支持,还需要很长的一段时间。

    一.函数
    最简单的实现模块的方式是使用函数。

    function add(x,y){
        return x+y;
    }
    function minus(x,y){
        return x-y;
    }
    

    如上将两个函数放在同一个 js 文件中,就实现了一个模块,使用的时候直接调用即可,如 add(1,2)。
    但是这样做会污染了全局变量,无法保证各模块间的变量名不冲突,并且模块成员之间看不出关系。

    二.对象
    再高级一点的实现模块的方式是使用对象。

    var myModule={
        a:1,
        b:2,
        add:function(x,y){
            return x+y;
        },
        minus:function(x,y){
            return x-y;
        }
    }
    

    如上,一般是使用一个对象实现一个模块,调用时直接使用对象调用属性的方式即可,如 myModule.add(1,2) 。
    使用这种方式,只要保证模块之间的名字不同,便可以避免模块间的变量名冲突,并且模块内的成员也有了一定的关系。但是使用这种方式的缺陷是外部可以随意更改模块内的成员,如可以直接在外部使用 module_text.a=0 ,更改模块内变量。

    三.立即执行函数
    更更高级的方式,是使用立即执行函数,在立即执行函数中返回一个对象。

    var myModule=(function(){
        var a=1,b=2;
    
        function add(x,y){
            return x+y;
        }
        function minus(x,y){
            return x-y;
        }
    
        return {
            add:add,
            minus:minus
        }
    })()
    

    如上,是通过立即执行函数来返回一个对象并赋给一个变量,调用方法对象模式,本质上这是一种对象模式。
    只是使用这种方法,我们可以通过控制返回对象中的变量来达到隐藏模块内成员的目的,上述代码中在外部我们并不能访问和修改模块内变量 a、b 的值。

    四.CommonJS
    自2009年 node.js 诞生后,javascript 模块化编程正式进入人们的视野,而 node.js 的模块化系统,便是参照 CommonJS 规范实现的。
    在 CommonJS 规范中,一个单独的文件就是一个模块,每个模块都有各自的作用域,即在一个模块(文件)中的变量、函数是私有的,外部无法访问。
    在模块内部,module 变量对象代表当前模块,它的 exports 属性也是一个对象,代表对外的接口,所以我们将需要对外暴露的内容放进 module.exprots 对象即可。

    //文件名为myModule
    var a=1,b=2;
    
    function add(x,y){
        return x+y;
    }
    function minus(x,y){
        return x-y;
    }
    module.exports = {
        add: add,
        minus: minus
    }
    

    然后我们可以通过 require 方法加载模块:

    //main.js文件中
    var myModule = require('./myModule.js');
    
    console.log(myModule.minus(2,1)); // 1
    

    但是,由于 require 加载模块的方式是同步加载,使得 CommonJS 规范不适合在浏览器端使用。在服务器端同步加载模块,等待时间取决于硬盘的读取时间,而在浏览器端同步加载模块,等待时间取决于网速快慢,这使得在等待加载模块的过程中,浏览器会处于‘假死’的状态。
    所以在浏览器端的模块化编程,一般采用 AMD 和 CMD 规范。

    五.AMD
    AMD 即 Asynchronous Module Definition,中文名是异步模块定义的意思。
    AMD 规范采用 define 函数定义模块
    define(id ?,dependencies ?,factory);
    第一个参数 id 是一个字符串文字,指定要定义的模块的 id。此参数是可选的,如果不存在,则模块 id 应默认为加载程序请求给定响应脚本的模块的 id。
    第二个参数是模块 ids 的数组文字,指被定义的模块所需的依赖关系。此参数是可选的。
    第三个参数 factory 是一个应该执行的函数来实例化模块或一个对象。如果 factory 是一个函数,它只能执行一次。如果 factory 是一个对象,则该对象应该被分配为模块的导出值。

    define('myModule',['moduleA','moduleB'], function(moduleA,moduleB){
        function doIt(){
            moduleA.doSomething();
            moduleB.doSomething();
        }
    
        return {
            doIt : doIt
        };
    });
    

    然后可以使用 require 函数加载模块,require 接收两个参数。
    第一个参数为所依赖的模块标识数组;
    第二个参数为回调函数,只有当全部的依赖模块加载完成后才会执行;

    require(['myModule'], function (myModule){
        myModule.doIt()
    });
    

    六.CMD
    CMD 即 Common Module Definition,中文名是通用模块定义的意思。
    CMD 规范推崇的是一个模块一个文件,遵循统一的写法。
    同样的 CMD 规范采用 define 函数定义模块
    define(factory)
    接收一个 factory 参数,可以是一个函数、对象或字符串。

    define(function(require, exports, module) {
        var $ = require('jquery.js')
        
        //do something
    });
    

    相关文章

      网友评论

        本文标题:前端模块化

        本文链接:https://www.haomeiwen.com/subject/kpyeyxtx.html