本文地址: 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 规范

    JavaScript 规范 全局命名空间污染与 IIFE 总是将代码包裹成一个 IIFE(Immediately-Invoked Function Expression),用以创建独立隔绝的定义域.这 ...

  2. 前端JavaScript规范

    前端JavaScript规范 http://www.imooc.com/article/1402 http://greengerong.com/blog/2015/05/09/qian-duan-ja ...

  3. [译]JavaScript规范-葵花宝典

    [译]JavaScript规范 译自:https://github.com/airbnb/javascript 类型 原始值: 相当于传值 string number boolean null und ...

  4. 前端编码风格规范(3)—— JavaScript 规范

    JavaScript 规范 全局命名空间污染与 IIFE 总是将代码包裹成一个 IIFE(Immediately-Invoked Function Expression),用以创建独立隔绝的定义域.这 ...

  5. 瞬间从IT屌丝变大神——JavaScript规范

    JavaScript规范主要包含以下内容: 底层JavaScript库采用YUI 2.8.0. 统一头部中只载入YUI load组件,其它组件都通过loader对象加载. JavaScript尽量避免 ...

  6. ECMA-262,第 5 版 最新 JavaScript 规范

    ECMA-262,第 5 版 最新 JavaScript 规范 Rob Larsen, 界面架构师, IBM 简介: 了解 ECMAScript 规范的历史,查看它的众多重要新特性和新概念. 发布日期 ...

  7. amazeui学习笔记二(进阶开发4)--JavaScript规范Rules

    amazeui学习笔记二(进阶开发4)--JavaScript规范Rules 一.总结 1.注释规范总原则: As short as possible(如无必要,勿增注释):尽量提高代码本身的清晰性. ...

  8. javascript 规范

    关于变量及方法等的命名,没有硬性规定,但是为了规范,遵循一些约定还是有必要的. 变量定义: 用var 关键字将要使用的变量定义在代码开头,变量间用分号隔开. 原因有二: 一是便于理解,知道下面的代码会 ...

  9. 前端javascript规范文档 (http://www.xuanfengge.com/category/web)

    说明:本文档为前端JS规范 一.规范目的 为提高团队协作效率,便于前端后期优化维护,输出高质量的文档. 二.基本准则 符合web标准,结构表现行为分离,兼容性优良.页面性能方面,代码要求简洁明了有序, ...

随机推荐

  1. hdu 4059 The Boss on Mars(纳入和排除)

    http://acm.hdu.edu.cn/showproblem.php?pid=4059 定义S = 1^4 + 2^4 + 3^4+.....+n^4.如今减去与n互质的数的4次方.问共降低了多 ...

  2. 系列二VS项目软件配置工具介绍

    原文:系列二VS项目软件配置工具介绍 Svn和VisualSvn介绍 在使用TortoiseSvn(SVN客户端)+ AnkhSvn(VS2008插件) +VisualSvn Server(版本控制服 ...

  3. Effective C++ -- 继承和面向对象设计

    32.确保你的public继承了模is-a关系 public继承意味着is-a关系(里氏替换原则),一切适用于基类也适用于派生类. 矩形继承正方形问题: 可实施与矩形的操作无法实施与正方形 在编程领域 ...

  4. StackExchange.Redis 使用-同步 异步 即发即弃 (三)

    访问单个服务器 有时候需要为单个服务器指定特定的命令 . IServer server = redis.GetServer("localhost", 6379); GetServe ...

  5. Quartz.net开源作业调度

    Quartz.net开源作业调度框架使用详解 前言 quartz.net作业调度框架是伟大组织OpenSymphony开发的quartz scheduler项目的.net延伸移植版本.支持 cron- ...

  6. mongodb.conf

    # mongodb.conf # Where to store the data. dbpath=/var/lib/mongodb #where to log logpath=/var/log/mon ...

  7. React JS高速新手教程

    翻译至官方文档<Tutorial>http://facebook.github.io/react/docs/tutorial.html 转载请注明出处:http://blog.csdn.n ...

  8. ASP.NET开发规范:OWIN

    ASP.NET开发规范:OWIN 今天投简历 准备面试了... 本节目录: OWIN简介 OWIN规范 Katana Hello World(3种Host) 自定义Middleware OWIN简介 ...

  9. (插播)unity的 异常捕捉和 ios Android 崩溃信息的捕捉。

    近期 做些准备性得工作和有意思的事情.所以近期做了一个适合ios和android 错误信息捕捉的unity插件. 两个功能,app崩溃也就是闪退 是开发人员 非常头疼的一件事,还有就是一些莫名得错误 ...

  10. ScrollView 在嵌套 ViewPager 时出现的问题

    1.在ViewPager 外面嵌套ScrollView 时导致ViewPager 中内容不显示,解决的办法是在ScrollView 标签下增加 android:fillViewport="t ...