转自:http://www.hicss.net/evolve-your-javascript-code/

方才在程序里看到一段JS代码,写法极为高明,私心想着若是其按照规范来写,定可培养对这门语言的理解,对JS编程能力提高必是极好的。说人话:丫代码写的太乱,看的窝火!

最近闲暇无事,准备对自己JS学习做一个总结。众所周知,JS是一种语法极其灵活的语言,一千个人会有一千种JS书写方式。这造成的结果往往就是给项目日后的开发及维护留下一个不小的隐患,也对你和团队再次开发及阅读代码造成一定困难,个人认为良好的书写规范是应该首当其冲的。所以参考一些优秀前端开发团队的代码规范后,总结了几点,希望能让你的Javascript代码上升一个台阶。

变量命名:

变量名包括全局变量,局部变量,类变量,函数参数等等,他们都属于这一类。

变量命名都以类型前缀+有意义的单词组成,用驼峰式命名法增加变量和函式的可读性。例如:sUserName,nCount。

前缀规范:

每个局部变量都需要有一个类型前缀,按照类型可以分为:

s:表示字符串。例如:sName,sHtml;
n:表示数字。例如:nPage,nTotal;
b:表示逻辑。例如:bChecked,bHasLogin;
a:表示数组。例如:aList,aGroup;
r:表示正则表达式。例如:rDomain,rEmail;
f:表示函数。例如:fGetHtml,fInit;
o:表示以上未涉及到的其他对象,例如:oButton,oDate;
g:表示全局变量,例如:gUserName,gLoginTime;

当然,也可以根据团队及项目需要增加前缀规范,例如我们团队会用到:

$:表示Jquery对象。例如:$Content,$Module;
一种比较广泛的Jquery对象变量命名规范。
j:表示Jquery对象。例如:jContent, jModule;
另一种Jquery对象变量命名方式。
fn:表示函数。例如:fnGetName,fnSetAge;
和上面函数的前缀略有不同,改用fn来代替,个人认为fn能够更好的区分普通变量和函数变量。
dom:表示Dom对象,例如:domForm,domInput;
项目中很多地方会用到原生的Dom方法及属性,可以根据团队需要适当修改。

这里可以根据项目及团队需要,设计出针对项目需要的前缀规范,从而达到团队开发协作便利的目的。

例外情况:

1:作用域不大临时变量可以简写,比如:str,num,bol,obj,fun,arr。
2:循环变量可以简写,比如:i,j,k等。
3:某些作为不允许修改值的变量认为是常量,全部字母都大写。例如:COPYRIGHT,PI。常量可以存在于函数中,也可以存在于全局。

为什么需要这样强制定义变量前缀?正式因为javascript是弱语言造成的。在定义大量变量的时候,我们需要很明确的知道当前变量是什么属性,如果只通过普通单词,是很难区分的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//普通代码
var checked = false;
var check = function() {
    return true;
}
/**
some code
**/
 
if(check) {//已经无法很确切知道这里是要用checked还是check()从而导致逻辑错误
    //do some thing
}
 
//规范后代码
var bChecked = false;
var fnCheck = function() {
    return true;
}
/**
some code
**/
 
if(bChecked) {
    // do some thing
}
if(fnCheck()) {
    // do other thing
}

函数命名:

统一使用动词或者动词+名词形式,例如:fnGetVersion(),fnSubmitForm(),fnInit();涉及返回逻辑值的函数可以使用is,has,contains等表示逻辑的词语代替动词,例如:fnIsObject(),fnHasClass(),fnContainsElment()。

如果有内部函数,使用_fn+动词+名词形式,内部函数必需在函数最后定义。例如:

1
2
3
4
5
6
7
8
9
10
11
12
function fnGetNumber(nTotal) {
    if (nTotal < 100) {
        nTotal = 100;
    }
    return _fnAdd(nTotal);
 
    function _fnAdd(nNumber) {
        nNumber++;
        return nNumber;
    }
}
alert(fGetNumber(10)); //alert 101

对象方法与事件响应函数:

对象方法命名使用fn+对象类名+动词+名词形式;例如 fnAddressGetEmail(),主观觉得加上对象类名略有些鸡肋,个人认为一个对象公开的属性与方法应该做到简洁易读。多增加一个对象类名单词,看着统一了,但有点为了规范而规范的味道,这里根据自身喜好仁者见仁智者见智吧。

某事件响应函数命名方式为fn+触发事件对象名+事件名或者模块名,例如:fnDivClick(),fnAddressSubmitButtonClick()

补充一些函数方法常用的动词:

get 获取/set 设置, add 增加/remove 删除
create 创建/destory 移除 start 启动/stop 停止
open 打开/close 关闭, read 读取/write 写入
load 载入/save 保存, create 创建/destroy 销毁
begin 开始/end 结束, backup 备份/restore 恢复
import 导入/export 导出, split 分割/merge 合并
inject 注入/extract 提取, attach 附着/detach 脱离
bind 绑定/separate 分离, view 查看/browse 浏览
edit 编辑/modify 修改, select 选取/mark 标记
copy 复制/paste 粘贴, undo 撤销/redo 重做
insert 插入/delete 移除, add 加入/append 添加
clean 清理/clear 清除, index 索引/sort 排序
find 查找/search 搜索, increase 增加/decrease 减少
play 播放/pause 暂停, launch 启动/run 运行
compile 编译/execute 执行, debug 调试/trace 跟踪
observe 观察/listen 监听, build 构建/publish 发布
input 输入/output 输出, encode 编码/decode 解码
encrypt 加密/decrypt 解密, compress 压缩/decompress 解压缩
pack 打包/unpack 解包, parse 解析/emit 生成
connect 连接/disconnect 断开, send 发送/receive 接收
download 下载/upload 上传, refresh 刷新/synchronize 同步
update 更新/revert 复原, lock 锁定/unlock 解锁
check out 签出/check in 签入, submit 提交/commit 交付
push 推/pull 拉, expand 展开/collapse 折叠
begin 起始/end 结束, start 开始/finish 完成
enter 进入/exit 退出, abort 放弃/quit 离开
obsolete 废弃/depreciate 废旧, collect 收集/aggregate 聚集

上面讨论了基本的JS书写命名规范,按我个人看法,只要能够按照上面的规范写出来的代码,一般不会太糟糕,最不济没人会说你代码乱的难以阅读。代码规范对于大团队的维护建设是毋庸置疑的,当然对于个人的代码素养也是很有帮助的,希望你能够通过上文能够加强你的代码规范,写出易读易维护的代码。

代码的规范属于战术上的进化,下面我们再来看看如何让你的Javascript在战略上进化。

面向对象书写Javascript

面向对象书写Javascript想必你一定不会陌生,但我敢说,大多数前端一般不会通过面向对象来书写JS代码。第一是Javascript本身的语言机制原因造成面向对象的书写困难,由于Javascript是原型式继承又是一个类C的语言,他的面向对象的东西相对于C++/Java比较奇怪。第二是Javascript作为一种语法极其灵活的语言,直接导致了面向对象书写JS又有多种写法,让许多初学者分不清到底哪个才是正确的写法。基于上述和个人的经验推荐如下俩种书写方式:

第一类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
(function(){
    function Circle(nRadius){
        this.nR = nRadius;
    }
    Circle.prototype = {
        PI : 3.14,
        fnGetArea : function(){
            return this.PI * this.nR * this.nR;
        }
    }
 
    var c1 = new Circle(5);
    alert(c1.fnGetArea()); //78.5
})();

上面这种可以说是很标准的面向对象JS书写方式了我们又称之为工厂模式,优点就是简单容易上手,新手常常喜欢这么写。以上代码略微做些改动,会有如下这个变种:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
(function(){
    function Circle(nRadius, sMessage){
        this.init.apply(this, arguments);
    }
    Circle.prototype = {
        init : function(nRadius, sMessage){
            this.nR = nRadius;
            this.sMessage = sMessage;
        },
        PI : 3.14,
        fnGetArea : function(){
            return this.sMessage + ": " + this.PI * this.nR * this.nR;
        }
    }
 
    var c = new Circle(5, "构造初始化 面积");
    alert(c.fnGetArea()); //构造初始化 面积: 78.5
})();

上面这个变种,就比较有意思了,this.init.apply(this, arguments);这行代码把初始化的任务交接给了init()方法,这么做的好处就是可以把所有初始化的东西都放在一个地方进行,增加可阅读性,需要理解一定的Javascript运行机制原理。

第二类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
(function(){
    function Circle(){
    }
    Circle.prototype = {
        init : function(nRadius, sMessage){
            this.nR = nRadius;
            this.sMessage = sMessage;
        },
        PI : 3.14,
        fnGetArea : function(){
            return this.sMessage + ": " + this.PI * this.nR * this.nR;
        }
    }
 
    var c = new Circle();
    c.init(5, "手动构造初始化 面积");
    alert(c.fnGetArea()); //手动构造初始化 面积: 78.5
})();

这类写法是我现在比较喜欢的写法,简洁高效。从书写角度来看省去了构造函数初始化属性,改用其init()中初始化。另一个好处在于不在new Circle()构造之初传入参数,个人认为当new构造对象的时候,最好不要掺杂参数,这样做很“危险”,改为“手动型”初始化更易于代码排查修改。当然这种写法还有一个原因就是他可以很好的转换成一般前端接受的“封装型”代码,我们把上面的代码也略微改动一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(function(){
    var Circle = {
        init : function(nRadius, sMessage){
            this.nR = nRadius;
            this.sMessage = sMessage;
        },
        PI : 3.14,
        fnGetArea : function(){
            return this.sMessage + ": " + this.PI * this.nR * this.nR;
        }
    }
 
    Circle.init(5, "封装型 面积");
    alert(Circle.fnGetArea()); //封装型 面积: 78.5
})();

是不是对上面这类代码很熟悉,很多网站上的例子都是使用这类封装型代码书写的,优点是代码的封装性良好,可以有效的重用,多用于页面功能性效果实现,封装一个Tab控件、封装一个跑马灯效果等等。缺点就是不能很好的用作继承,这是和上面三种格式最大区别。可话又说回来一般JS代码很少会用到继承的地方,除非是写一个大型库(类似YUI)会用到继承外,一般写一个功能模块用到封装型代码就够用了,所以大多数前端喜欢使用这类封装型的书写风格。

上面介绍了2类4种面向对象的写法,一般面向对象书写格式基本都在上面了,熟悉面向对象书写可以有效的增加你对JS的理解。熟练使用上面4中写法也能够很好的在工作中给代码维护修改带来便利。最后我们再来谈一个技巧,让你的Javascript代码在技巧上进化。

用对象字面量构造对象

一个对象字面量就是包含在一对花括号中的0个或多个“名/值”对。上文在面向对象书写格式的时候我们就大量的使用了对象字面量的书写格式。

对象字面量书写Javascript可以很好的简化代码,又能极大的增加代码可读性,尤其作为参数使用可以有化腐朽为神奇的表现。我们看下面代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
(function(){
    function Person(sName, nAge, nWeight, bSingle){
        this.sName = sName;
        this.nAge = nAge;
        this.nWeight = nWeight;
        this.bSingle = bSingle;
    }
    Person.prototype.showInfo = function(){
        return this.sName + " " + this.nAge + " " + this.nWeight + " " + this.bSingle;
    }
    var p = new Person("海玉", 25, 75, true);
    alert(p.showInfo()); //海玉 25 75 true
})();

上面是一个很标准的工厂模式,一般而言这类写法属于那种规规矩矩没有大错也没有亮点的代码,而且参数不少,一个不小心还会传入错误的参数,而应用对象字面量技巧可以很好的规避此类问题,我们来看改动过后的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
(function(){
    function Person(){
    }
    Person.prototype = {
        init : function(option){
            if(typeof option == "undefined"){
                option = {};
            }
            this.sName = option.sName || "海玉";
            this.nAge = option.nAge || 25;
            this.nWeight = option.nWeight || 75;
            this.bSingle = (typeof option.bSingle != "undefined") ? option.bSingle : true;
        },
        showInfo : function(){
            return this.sName + " " + this.nAge + " " + this.nWeight + " " + this.bSingle;
        }
    }
    var p = new Person();
    p.init({
        nWeight : 80,
        sName : "Hank"
    })
    alert(p.showInfo()); //Hank 25 80 true
})();

这里使用第三种面向对象写法,有兴趣的朋友可以自行尝试改成封装型写法。上面的改写看出哪里改动最大吗?对的,传入参数改成了一个对象字面量,而且传入参数可以是随意设置,位置颠倒也不会有任何问题。这里充分利用对象字面量优点,利用键值对代替原始的传参方式大大提升了可读性和容错性。还有一个改进就是默认值的处理,如果没有传入任何参数,此代码也能很好的运行下去,不会有任何问题。

注1:这里形参命名为option,没有遵守上面的变量命名规范是为了方便书写与阅读,具体情况具体分析。
注2:由于||运算符对于布尔值默认赋值会出现赋值问题,所以要先进行判断是否为undefined,再利用三元运算符可以很好的完成布尔值的默认值赋值。

总的来说上面阐述的代码进化只能算的上是“修身”层面,想要真正的让代码“修心”还是得多写,多看,多练。只有这样你的代码才会更精练,更有扩展性,更好的维护性。

林林总总写了这些个总结,一来是对自己学习的记录,二来也是想同大家探讨JS还有哪些地方有潜力可挖,脑子里还有许多零零碎碎的片段,待日后再次整理验证再与大家一起分享吧。

引爆你的Javascript代码进化的更多相关文章

  1. 引爆你的Javascript代码进化 (转)

    转自 海玉的博客 方才在程序里看到一段JS代码,写法极为高明,私心想着若是其按照规范来写,定可培养对这门语言的理解,对JS编程能力提高必是极好的.说人话:丫代码写的太乱,看的窝火! 最近闲暇无事,准备 ...

  2. 前端福利!10个短小却超实用的JavaScript 代码段

    JavaScript正变得越来越流行,它已经成为前端开发的第一选择,并且利用基于JavaScript语言的NodeJS,我们也可以开发出高 性能的后端服务,甚至我还看到在硬件编程领域也出现了JavaS ...

  3. 编写可维护的javascript代码---开篇(介绍自动报错的插件)

    文章开篇主要推荐了2款检测编程风格的工具: JSLint和JSHint: jsLint是由Douglas Crockford创建的.这是一个通用的javascript代码质量检测工具,最开始JSLin ...

  4. Google JavaScript代码风格指南

    Google JavaScript代码风格指南 修正版本 2.28 Aaron Whyte Bob Jervis Dan Pupius Eric Arvidsson Fritz Schneider R ...

  5. javascript代码 调试方法

    你的代码可能包含语法错误,逻辑错误,如果没有调试工具,这些错误比较难于发现. 通常,如果 JavaScript 出现错误,是不会有提示信息,这样你就无法找到代码错误的位置. 在程序代码中寻找错误叫做代 ...

  6. 7个高性能JavaScript代码高亮插件

    本文由码农网 – 小峰原创,转载请看清文末的转载要求,欢迎参与我们的付费投稿计划! 对于喜欢写技术博客的同学来说,一定对代码高亮组件非常熟悉.一款优秀的JavaScript代码高亮插件,将会帮助你渲染 ...

  7. JavaScript代码段整理笔记系列(二)

    上篇介绍了15个常用代码段,本篇将把剩余的15个补齐,希望对大家有所帮助!!! 16.检测Shift.Alt.Ctrl键: event.shiftKey; //检测Shift event.altKey ...

  8. JavaScript代码段整理笔记系列(一)

    30段JavaScript代码——上篇 1.如何区分IE及非IE浏览器: if(!+[1,]){ //IE 11 不支持 alert("这是 IE 浏览器"): }else{ al ...

  9. 如何让你的JavaScript代码更加语义化

    语义化这个词在 HTML 中用的比较多,即根据内容的结构化选择合适的标签.其作用不容小觑: 赋予标签含义,让代码结构更加清晰,虽然我们可以在标签上添加 class 来标识,但这种通过属性来表示本体的形 ...

随机推荐

  1. 基于WebQQ3.0协议写一个QQ机器人

    最近公司需要做个qq机器人获取qq好友列表,并且能够自动向选定的qq好友定时发送消息.没有头绪,硬着头皮上 甘甜的心情瞬间变得苦涩了 哇 多捞吆 1.WEBQQ3.0登陆协议 进入WEBQQ, htt ...

  2. HTTP是用来做什么的

    (一)HTTP协议介绍 超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议.所有的WWW文件都必须遵守这个标准.设计HTTP最初的目 ...

  3. windows环境安装zabbix客户端

    安装windows版zabbix客户端 一.下载客户端 在数据盘新建一个zabbix_agent目录 浏览器打开 https://www.zabbix.com/download_agents 选择”z ...

  4. target=_blank攻击

    [target=_blank攻击] 在<a>标签中加入 rel="noopener noreferrer" 来避免. 参考:https://mathiasbynens. ...

  5. select字符串

    [select字符串] select通常用于选择某中的某一列.如有表Download: 通常用select选择某一列,如: 当select一个字符串时,则会返回如下值: 结论:select中传递一个字 ...

  6. Fiddler抓包域名过滤(转载)

    转载自 http://www.cnblogs.com/111testing/p/6440480.html Fiddler抓包域名过滤 我们在用Fiddler抓包的时候会抓到很多不需要的数据包,我们怎样 ...

  7. 第二章 向量(b)可扩充向量

  8. JS中取得<asp:TextBox中的值

    var s = document.getElementById("<%=txt_DaShen.ClientID %>").value; 注:txt_DaShen 为as ...

  9. stm32学习基本知识点

    1.AHB系统总线分为APB1(36MHz)和APB2(72MHz),其中2>1,意思是APB2接高速设备 2.Stm32f10x.h相当于reg52.h(里面有基本的位操作定义),另一个为st ...

  10. 大数据分析界的“神兽”Apache Kylin有多牛?【转】

    本文作者:李栋,来自Kyligence公司,也是Apache Kylin Committer & PMC member,在加入Kyligence之前曾就职于eBay.微软. 1.Apache ...