改善javascript代码结构

首先看下常规开发中javascript非结构化组织代码

function appInit () {
    //程序初始化操作
}

function appModule1 () {
   //程序功能模块1   
}

function appModule2 () {
   //程序功能模块2   
}

function appModule3 () {
   //程序功能模块3   
}

$( document ).ready(appInit )

 

从技术角度看,这种代码方式并没有任何错误,但是通过下图可以发现这些函数都是建立在全局名称空间下

若在全局名称空间中创建很多变量很快会导致严重的问题、比如在全局名称空间中定义了名为i、_或$的变量。

如何改善呢?

1、使用一个单例创建一个应用程序名称空间

var myApp = {
    init : function () {
         //程序初始化操作
    },
    appModule1 : function () {
        //程序功能模块1
    },
    appModule2 : function () {
        //程序功能模块2
    },
    appModule3 : function () {
        //程序功能模块3
    }
}
$( document ).ready(myApp.init)

对于上面的新结构,打开chrome查看window下的属性时仅看到单个变量myApp,这中方式极大的降低了变量名冲突的可能性。

这一模式允许多个开发人员跨越多个文件,在单个应用程序名称空间之下进行协同开发。从代码结构角度来说,可以将网站的每一部分拆成独立文件。比如本例中的common.js、

appModule1.js、appModule2.js和appModule3.js。每个开发人员都有一个自己负责的网站部分和相应的javascript文件,开发人员只需要关注自己的文件,不需要担心会发生冲突。

 

common.js

var myApp = {
    common : {
           init : function () {
                 //初始化应用程序通用代码
           }
    }
}

appModule1.js

myApp.appModule1 = {
     init : function () {
          //初始化代码
     },
     update : function () {
         //更新模块1的代码
     },
     render : function () {
         //呈现模块1的代码
     }
}

appModule2.js

myApp.appModule2 = {
     init : function () {
          //初始化代码
     },
     update : function () {
         //更新模块2的代码
     },
     render : function () {
         //呈现模块2的代码
     }
}

appModule3.js

myApp.appModule3 = {
     init : function () {
          //初始化代码
     },
     update : function () {
         //更新模块3的代码
     },
     render : function () {
         //呈现模块3的代码
     }
}

 

2、Module模式

      模块模式是单例的一种变种,增强了单例模式提供的封装性,并增加了创建私有方法和私有属性的功能

      模块模式包含三个主要组件:一个与前面例子类似的命名空间、一个立即执行函数和函数返回对象,该返回对象包含公有方法和公有属性,js代码如下:

//app的名称空间。传入jquery对象以缩短查找过程
var myApp = function( $ ){
    //私有变量和方法
    var message = " i am a module ";
    function multiplier (x,y) {
        return x * y;
    };
    //返回对象包含公有属性和方法
    return {
        init:function(){
            //初始化app
        },
        prop : '42',
        getProduct : function(){
            //访问私有方法
            return multiplier(2,3);
        },
        shareMessage : function (arg){
            //对私有属性进行限制访问
            if(arg == "admin"){
                return message;
            } else {
                throw new Error("No access");
            }
        }
        
    }
}(jQuery)

控制台中测试如下:

     扩展该模式以增加更多的模块也非常简单。如下代码:

myApp.module1 = function($){
    //私有变量和方法
    var config = {
        "color":"red",
        "title":"module1",
        "width":"20px"
    };
    return {
        init:function(){
            //初始化module1
        },
        updateConfig : function(obj){
            config.color = obj.color || config.color;
            config.title = obj.title || config.title;
            config.width = obj.width || config.width;
        },
        render:function(){
            var $module1 = $("#id");
            $module1.text(config.title)
                    .css({"width":config.width,"color":config.color})
            
        }
    }
    
}(jQuery)

该代码描述了一个module1模块,它包含一个私有配置对象和一个公共方法,该公有方法允许根据一组预定义条件获得对module1配置的访问,类似于java中private和public关键字的使用。在js开发中,并非所以时候都需要使用这种保护访问,但当我们需要实现这样功能时,使用模块模式是非常重要的。