本文地址: http://www.hicss.net/evolve-your-javascript-code/javascript
方才在程序里看到一段JS代码,写法极为高明,私心想着如果其按照规范来写,定可培养对这门语言的理解,对JS编程能力提升必是极好的。说人话:丫代码写的太乱,看的窝火!css
最近闲暇无事,准备对本身JS学习作一个总结。众所周知,JS是一种语法极其灵活的语言,一千我的会有一千种JS书写方式。这形成的结果每每就是给项目往后的开发及维护留下一个不小的隐患,也对你和团队再次开发及阅读代码形成必定困难,我的认为良好的书写规范是应该首当其冲的。因此参考一些优秀前端开发团队的代码规范后,总结了几点,但愿能让你的Javascript代码上升一个台阶。前端
变量命名:java
变量名包括全局变量,局部变量,类变量,函数参数等等,他们都属于这一类。正则表达式
变量命名都以类型前缀+有意义的单词组成,用驼峰式命名法增长变量和函式的可读性。例如:sUserName,nCount。编程
前缀规范:数组
每一个局部变量都须要有一个类型前缀,按照类型能够分为:app
s:表示字符串。例如:sName,sHtml;
n:表示数字。例如:nPage,nTotal;
b:表示逻辑。例如:bChecked,bHasLogin;
a:表示数组。例如:aList,aGroup;
r:表示正则表达式。例如:rDomain,rEmail;
f:表示函数。例如:fGetHtml,fInit;
o:表示以上未涉及到的其余对象,例如:oButton,oDate;
g:表示全局变量,例如:gUserName,gLoginTime;dom
固然,也能够根据团队及项目须要增长前缀规范,例如咱们团队会用到:函数
$:表示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还有哪些地方有潜力可挖,脑子里还有许多零零碎碎的片断,待往后再次整理验证再与你们一块儿分享吧。