zoukankan      html  css  js  c++  java
  • [javascript]模块化&命名污染—from 编程精解

      最近看了编程精解里面的模块化一章,很受启发。

      /****************/

      在开发的实际过程中,根据页面或者逻辑布局,js代码可以按照功能划分为若干个区块:数据交互、表单验证、页面布局等等模块

      为了提高开发效率和后期代码维护,很自然的应该将几十个js函数划分为模块,利于调试和后续修改。但写出几十个函数的时候,命名自然就出现问题了,想不出别的函数名或者干脆两个函数重名了,这种因为重复声明而导致的bug称为命名污染,这在大型项目中很常见。

      提到模块开发,最容易想到的是通过js文件来分模块存储和调用代码。而文件存储的弊病是:比如首页加载了3,4个js文件(应该不算多),不同文件里面的全局变量,包括函数和变量,怎么保证不存在命名冲突,当然,通过给变量名和函数名前加前缀是一个很笨但是很奏效的办法,有没有什么办法能够从最基础上避免这种命名污染、同时能够实现代码模块化呢?

      

      1.通过模块对象来实现。

        举一个书中的例子,要做一个月份翻译器,把1翻译为一月。对于新手来讲很可能是这样的:

           

    var names = ['一','二','三','四','五','六','七','八','九','十','十一','十二'];
    function getMonthName(num){
        return names[num-1]+'月';
    };
    function getMonthNum(str){
        for(var i in names){
            if( str == (names[i]+'月')){
                return i+1;
            }
        }
    };

      这里面的names和getMonthName,getMonthNum的生存域都是顶级的,所以如果其他文件或者js代码中声明了名字为names的变量,就会导致程序异常(getMonthName,getMonthNum这么长的名字一般很少重复)。

      在一个后台管理网站里面,需要写的函数可能有:表单验证、图片轮播组件、dom加载、从某input里面读数据再拼成json、hover效果、弹出层....如果这些功能或者插件都是直接声明全局函数或全局变量,想命名就会想哭的。

      

      所以这时候,应该想到利用函数闭包来避免产生作用域命名污染,上面代码的最简修改就是

      

    //匿名函数声明并直接调用
    //names作为局部变量出现 不会污染顶级作用域,外部无法访问
    //通过为顶级作用域的window对象绑定函数的方式,对外暴露接口
    (function(){
        var names = ['一','二','三','四','五','六','七','八','九','十','十一','十二'];
        window.getMonthName = function getMonthName(num){
            return names[num-1]+'月';
        };
        window.getMonthNum = function getMonthNum(str){
            for(var i in names){
                if( str == (names[i]+'月')){
                    return i+1;
                }
            }
        };
    })();

      这种方法也有不好的地方,我们总不能把所有的函数接口都绑定到window对象的属性当中,那和直接在代码里声明函数没区别。

      所以,再一步优化就是做模块对象,很简单的优化,把函数绑定到模块对象上,通过访问模块对象的属性来调用功能:

      

      

    var monthTranslator = (function(){
        var names = ['一','二','三','四','五','六','七','八','九','十','十一','十二'];
        return {
            getMonthName:function(num){
                return names[num-1]+'月';
            },
            getMonthNum:function(str){
                for(var i in names){
                    if( str == (names[i]+'月')){
                        return i+1;
                    }
                }
            }
        };
    })();

      上面的函数调用时,直接使用 monthTranslator.getMonthName(1);  就可以了。当然也可以把names作为模块对象的属性出现,这就看功能设计了。

      /*************/

      上面说的这些就是js代码的模块化,这个见仁见智,有的人可能觉得你这种写法有什么用处呢,“我自己想个命名前缀不就得了,有必要写这么麻烦的函数么”

      但是我觉得,良好的代码风格是一个程序员的优良品德。对人对己,都是极好的。

      

    [补]1.继承方式的实现:冒充对象

     1 function Parent(){
     2     this.name = 'parent';
     3     this.count = 0;
     4     this.info = function(){
     5         return [this.name,':',this.count.toString()].join('');
     6     }
     7 }
     8 function Son(){
     9     this.inherit = Parent;
    10     this.inherit();
    11     delete this.inherit;
    12     this.flag = 'son';
    13     this.count = 1;
    14 }
    15 var son = new Son();    

    [补]2.继承方式的实现:原型链的修改和维护 对象.constructor = 构造器.prototype.constructor(原型链末端闭环)

    function Parent(){
        this.name = 'parent';
        this.count = 0;
        this.info = function(){
            return [this.name,':',this.count.toString()].join('');
        }
    }
    function Son(){
        this.constructor = arguments.callee;
        this.flag = 'son';
        this.count = 1;
    }
    Son.prototype = new Parent();
    var son = new Son();
  • 相关阅读:
    前端mvc mvp mvvm 架构介绍(vue重构项目一)
    SPA页面缓存再优化二
    消除浏览器对input输入框的自动填充
    单页面系统的一些性能优化
    城市联动组件插件思想分析
    前端性能优化点总结
    ui-router 1.0以上的 $stateChangeStart
    (转) view视图的放大、缩小、旋转
    (转)代码中实现button
    objective-c 强弱引用、properties的学习
  • 原文地址:https://www.cnblogs.com/limingxi/p/4020427.html
Copyright © 2011-2022 走看看