日期:2014-05-16  浏览次数:20381 次

JavaScript重构(四):JavaScript编码规则

没有规矩,不成方圆,JavaScript带来了灵活性,也带来了不受控的变量和访问,所以要用规则限制它。一支成熟的团队,还是一支新鲜的团队,规则应当是不一样的,我只是列出一些常见的或者有效的办法,来约束跳跃的开发人员,思维可以任意飞跃,代码却要持续受控。当然,任何规则都是建立在一定的认知基础之上的,面向对象JavaScript的基础是必备的,否则一切无从谈起。

?

变量和方法控制:

模块开发不允许存放独立的全局变量、全局方法,只允许把变量和方法放置到相应模块的“命名空间”中,对此的解释请参见此文。实在心痒了,那么使用匿名函数如何?

(function() { 
  var value = 'xxx'; 
  var func = function() {...}; 
})();

?

模块化需要严格控制住代码的区域性,这不仅仅是代码可维护性、可定制性的一方面,同时也让JavaScript引擎在属性和方法使用完毕后及时地回收掉。

不允许在模块代码中污染原生对象,例如

String.prototype.func = new function(){...}; 

?

如此的代码必须集中控制,例如统一放置在common.js中,严格保护起来。

?

数据存放约束:

普通变量、prototype变量和function变量分而治之,方法名一律大写开头,变量名还是遵从骆驼命名法如何:

function T(name){ 
  T.prototype._instance_number++; 
  this.name = name; 
  this.showName=function(){ 
    alert(this.name); 
  } 
}; 
T.prototype = { 
  _instance_number:0, 
  getInstanceNum: function(){ 
    return T.prototype._instance_number; 
  } 
}; 

var t = new T("PortalONE"); 
t.showName(); 
new T("Again"); 
alert(t.getInstanceNum()); //打印:2

?

这里有意做了一件事情,T内部的属性和私有方法使用下划线开头,这样很好地实现了封装(上述代码中如果使用t.instanceNum,是无法访问到这个值的),如果这段代码都看不懂的话,赶紧温习一下JavaScript的面向对象吧 :)。JavaScript中提供了闭包和原型两种办法来实现继承和多态,关于重构中应用这一点,后续的章节我再啰嗦吧。

另外,优先使用JavaScript的原生对象和容器,比如Array,Ajax的数据类型统一切到JSON上来,尽量不要使用隐藏域;另外,通常是不允许随意扩展DOM对象的。

?

利用闭包特性,这一点可以做得更优雅:

var User = function(){
    var name;
    this.setName = function(newName){
        name = newName;
    };
    this.getName = function(){
        return name;
    };
};

访问的时候具备如下封装效果:

var user = new User();
user.setName("abc");
alert(user.getName()); //abc
alert(user.name);         //undefined

?

至于模块间的通信:模块间的通信意味着模块间的耦合性,是需要严格避免的;通信的途径通常使用方法级属性或者模块级的prototype变量。

?

DOM操纵规则:

在模块代码中,通常要求把对DOM的操纵独立到模块js中,应当避免在DOM模型上显示地写时间触发函数,例如:

<div onclick="xxx" />

借助JQuery基于bind的一系列方法,把行为逻辑独立出来以后,完全可以看到清爽的HTML标签。

DOM对象的访问通常使用id来查找,偶有根据name来查找的,过多次数地、不合理地遍历DOM树是前端性能保持的大忌。

?

CSS的样式控制:

(1)尽量拒绝style="xxx"的写法,主要目的是将样式统一到主题样式表单中,当然主题样式表单也是按模块存放的,对于不同语种的定制和不同风格的切换带来便利。

(2)规约JavaScript对样式的操纵,理想状况下,封装性好的UI可以自由地替换它的样式集合。

?

以上只能算冰山一角,抛砖引玉,实际项目中需要在开发过程中逐步细化和完善。

?

文章系本人原创,转载请注明作者和出处

1 楼 Dev|il 2012-02-10  
引用:这里有意做了一件事情,T内部的属性和私有方法使用下划线开头,这样很好地实现了封装(上述代码中如果使用t.instanceNum,是无法访问到这个值的)

楼主你的上述代码中哪里出现聊instanceNum这个属性,如果是_instance_number,那t._instance_number也能够访问
2 楼 RayChase 2012-02-11  
Dev|il 写道
引用:这里有意做了一件事情,T内部的属性和私有方法使用下划线开头,这样很好地实现了封装(上述代码中如果使用t.instanceNum,是无法访问到这个值的)

楼主你的上述代码中哪里出现聊instanceNum这个属性,如果是_instance_number,那t._instance_number也能够访问

可能是我这里描述不清晰,这里包含两种方式:

一种办法是给类成员变量添加下划线,比如this.userName变成this._user_name,这样表示其为私有变量,外部不要随便访问;

还有一种方式是利用闭包的特点来完成,我补充在文中了:
var User = function(){ 
    var name; 
    this.setName = function(newName){ 
        name = newName; 
    }; 
    this.getName = function(){ 
        return name; 
    }; 
};
效果:
alert(user.getName()); //abc 
alert(user.name);      //undefined
3 楼 踏月流星 2012-02-22