美文网首页Javascript程序员首页投稿(暂停使用,暂停投稿)
[JavaScript]技术选型:模块化与框架(一)

[JavaScript]技术选型:模块化与框架(一)

作者: 普通一般社会人 | 来源:发表于2016-03-03 04:10 被阅读454次
    本文总结自网易云课堂-前端工程微专业课程

    模块组织(js脚本)

    在构件具有一定规模的项目时,我们往往采用分割的形式,将一个项目中拆分成一个个的小模块,这样在开发和维护时,会简单许多。而在不同的模块中,我们只需考虑模块输出的接口就可以了。但是在ES5及以下版本的规范中,模块并没有原生支持。那么如何编写我们的代码,来巧妙的弥补这一缺陷呢?

    模块职责:

    封装实现
    暴露接口
    声明依赖(主要是模块系统职责)

    1.反模块

    反模块即不使用任何的模块系统,所编写的函数都散落在全局当中,无封装性,也没有明显的接口暴露,调用函数也没有依赖声明。这样的做法是很危险的,因为你的变量在全局中,大家都可以拿来修改,特别是出现重名变量的时候,就会出现冲突。

    2.字面量

    var math = {
        add: function add(a, b){
            return a+b;
        },
        sub: function sub(a, b){
            return a-b;
        }
    }
    //声明一个math对象,有两个方法,我们很明显的可以看出,这个模块输出的方法很直观。
    var calculate = {
        action: "add",
        compute: function compute(a, b){
            switch(this.action){
                case "add": return math.add(a, b);
                case "sub": return math.sub(a, b);//调用的时候也很简单。
            }
        }
    } 
    
    

    由上可以看出,字面量清楚的描述了接口是什么,但是却没有访问限制,并且调用时也没有依赖声明。也就是说,这个模块没有被封装起来,我们可以在全局中任意的修改其中的所有属性和方法。

    3.IIFE(自执行函数表达式)

    var calculate = (function(){
        var action = "add";
        return{
        compute: function compute(a, b){
            switch(action){
                case "add": return math.add(a, b);
                case "sub": return math.sub(a, b);
            }
        }
        }
    } )();
    //在js中,函数闭包能保存函数的上一级中变量的状态,所以这段代码在执行之后,action变量无法被改变,但却可以被使用(仅在return出的函数中)。
    

    IIFE的方法实现了私有变量的访问控制,但依然没有对应的依赖声明,由此,变出现了下面的这种形式:

    var calculate = (function(m){//这里的m即传入的math
        var action = "add";
        function compute(a, b){
            switch(action){
                case "add": return m.add(a, b);
                case "sub": return m.sub(a, b);
            }
        }
        return{
            compute: compute//返回一个名叫compute的方法,这个方法是compute函数
        }
    })(math);//把math作为自执行函数的参数传入
    
    

    这样,使用的也是IIFE方法,并且对于暴漏的接口也更方便去查找和更改。并且有了对依赖的声明,只是我们需要手动去管理依赖,并且对于模块的加载顺序也有要求,被依赖的模块必须首先被加载。并且会污染全局变量(var calculate有重名风险)。

    4.命名空间

    为了避免IIFE污染全局变量的风险,我们采用一种统一命名的方式,来解决这个问题。

    var namespace = (function(){//namespace函数用来缓存所有的模块,并且返回当前组件。
        var cache = {};//缓存所有模块
        function createModule(name, deps, definition){
            console.log(arguments.length);
            if(arguments.length == 1) return cache[name];
    
            deps = deps.map(function(depName){
                return cache[depName];//将依赖组件从cache中抽出
            })
            //程序的主体部分在此执行,并且把返回的接口保存在cache中
            cache[name] = definition.apply(null, deps)//将依赖组件当成参数传入调用函数中,这样,调用函数中便有了依赖组件。
    
            return cache[name];
        }
        return createModule;
    })()
    
    namespace("math", [], function(){//模块声明,依赖声明,以及模块构成
        function add(a, b){return a+b}
        function sub(a, b){return a-b}
    
        return{//返回需要暴漏的接口
            add: add,
            sub: sub
        }
    });
     
    namespace("calculate", ["math"], function(m){
        var action = "add";
        function compute(a, b){
            return m[action](a, b);
        }
        return{
            compute: compute
        }
    });
    
    
    

    但是我们依然需要手动的去管理依赖,那么,使用什么办法才能够解决手动依赖的弊端呢?这就需要使用民间的模块系统来处理了。

    相关文章

      网友评论

      本文标题:[JavaScript]技术选型:模块化与框架(一)

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