欢迎通过电子邮件
联系我
JavaScript初学者的二十四条最佳实践
code, 24 june, 2009
非常不严格地译自Jeffrey Way的《24 JavaScript Best Practices for Beginners》,下文包含本人个人之可能不准确理解,外语良好者请移步原文。
特别提醒:原文实际只有23条“最佳实践”,并非译文遗漏。
-
用“===”替代“==”
JavaScript提供了2对比较运算符:“=== | !==”和“== | !=”,最佳实践是总是用第一对来进行比较。
“=== | !==”是严格的比较运算,它们不仅对比值,而且对比数据类型。
var x=4;
var y='4';
if (x==y){
alert('x and y are equal.');
}
if (x===y){
alert('x and y are identical.');
} -
绝不使用“eval”
“eval”通过执行字符串中的JavaScript代码。不仅是因为使用“eval”会导致性能的降低,更因为它带来了太多的安全隐患,所以,绝对不要使用“eval”。
替代“eval”的方法是编写作为递归的JavaScript解释器的程序,或者编写动态生成并且计算JavaScript代码的后台程序。
-
不要使用简写
JavaScript允许你忽略掉花括号和分号结束符,大多数浏览器会正确的执行以下代码:
if(someVariableExists)
x=false然而请考虑以下情况:
if(someVariableExists)
x=false
anotherFunctionCall();您或许会认为它等同于:
if(someVariableExists){
x=false;
anotherFunctionCall();
}但实际上浏览器会执行为:
if(someVariableExists){
x=false;
}
anotherFunctionCall();正如你看到的那样,跨行代码省略掉花括号是一个可怕的实践。
行内花括号是可以省略的,但这仍然是一个非常有争议的行为:
if(2+2===4) return 'nicely done';在简写代码的时候,请记住:永远为将来考虑,无论如何,你很有可能需要再次面对你曾经写过的代码。
-
使用JSLint
JSLint是一个Douglas Crockford开发的调试器,它可以在你的代码中发现一些常见的问题。在正式发布你的代码之前,确保它可以通过JSLint,以免出现一些意外问题。
-
将JavaScript代码放在页面的最后
这条实践已经不是第一次被提及,鉴于其重要程度,我愿意在这里再次重申。
切记,让用户尽快看到页面是最重要的事情,当JavaScript代码被载入完全之前,浏览器不会去加载其他的对象,这将造成不良的用户体验。
将你的代码放在body关闭之前的一行,这绝对是一个重要的最佳实践。
-
在“for”之外申明变量
这似乎是废话:不要让引擎执行任何多余的语句:
for(var i=0;ivar container=document.getElementById('container');
container.innerHtml+='my number:'+i;
console.log(i);
}以上代码无数次的遍历了DOM,无数次的申明了一个相同的对象,非常地低效。
var container=document.getElementById('container');
for(var i=0,len=someArray.length;i<len;i++){
container.innerHtml+='my number:'+i;
console.log(i);
}你应该留意到了这段循环有点不同,延伸阅读一篇来自于Robert Nyman关于循环效率的文章《JavaScript loop performance》,高手总是能在最常见的场景中发现不寻常之处。
-
更快地创建字符串对象
当需要遍历一个类似数组一样的对象时,不要总是下意识的“for”,尽可能多地使用类似“join”这样的原生方法。
var arr=['item 1','item 2','item 3'];
var list='<ul><li>' + arr.join('</li><li>') + '</li></ul>'; -
减少全局量
减少全局量,即增加兼容性。
var name='Jeffrey';
var lastName='Way';
function doSomething(){
}
……
console.log(name); // Jeffrey or something surprised
与其他人的代码整合时,冲突往往是暴露的全局量造成的,良好的闭包习惯应该成为程序员的公德。
var DudeNameSpace={
name:'Jeffrey',
lastName:'Way',
doSomething:function(){
}
}
……
console.log(DudeNameSpace.name); // Jeffrey -
注释代码
这似乎是废话,但请想像你需要修改几个月前的代码,或接受其他人写的代码,却不知道如何下手的场景。书写有良好阅读性的注释,同样应该成为一条重要的程序员公德。
-
渐退兼容
禁用浏览器的JavaScript功能,确保你的页面在此情况下也能正确地被执行。如果你重视浏览器兼容,那么更应该重视渐退兼容。
-
不在“setInterval”或“setTimeOut”中直接使用字符串
setInterval(
"document.getElementById('container').innerHTML+='My new number:'+i",3000
);把字符串操作封装在函数中后,再置于“setInterval”或“setTimeOut”中。
-
不使用“with”
“with”可以方便地用来引用某个特定对象中已有的属性。
“with”可缩短特定情形下的代码并使得代码具备更好的可读性,在上个世纪一度非常流行,例如以下代码:
being.person.man.bodyparts.arms=true;
being.person.man.bodyparts.legs=true;可以简写为:
with (being.person.man.bodyparts){
arms=true;
legs=true;
}后来程序员们发现,在大量使用“with”时,出现了很多意外情况,原因是“with”会把参数对象加入到{}代码块执行环境(execution context)里的作用域链(scope chain)首部,从而修改了索引对象的顺序,造成混乱。可以参考文章《JavaScript Execution Context, Closure, Eval and “this” Keyword》或《JavaScript作用域链初探》。
另外,“with”不能用来给对象添加属性,要给对象创建新的属性,必须明确地引用该对象。
所以,使用“var”替代“with”:
var o=being.person.man.bodyparts;
o.arms=true;
o.legs=true; -
用{}替代New Object()
创建一个新对象的方法有很多,最传统的莫过于:
var o=new Object();
o.name='Jeffrey';
o.lastName='Way';
o.someFunction=function(){
console.log(this.name);
}如果只需要一个空对象,那么{}是最好的方法,所以,下面这个方法更加强健:
var o={
name:'Jeffrey',
lastName='Way',
someFunction:function(){
console.log(this.name);
}
}; -
用[]替代New Array()
与上一条理由类似。
var a=new Array();
a[0]="Joe";
a[1]='Plumber';var a=['Joe','Plumber']; -
用逗号减少不必要的“var”申明
var someItem='some string';
var anotherItem='another string';
var oneMoreItem='one more string';毫无疑问,下面一句执行得更快。
var someItem='some string',anotherItem='another string',oneMoreItem='one more string'; -
任何时候不要省略分号结束符
尽管大多数浏览器允许省略掉每行代码最后的分号结束符,但是为了避免潜在的风险,养成每行结束前加一个分号,无疑是一条重要的最佳实践。
-
“For in”声明中对对象属性的检测
“For in”声明用于对数组或对象的属性进行循环操作,循环中的代码每执行一次,就会对数组的元素或对象的属性进行一次操作。
所以在用于对象的属性循环操作时,增加一个对对象属性的判断,以提高代码运算速度。
for(key in object){
if(object.hasOwnProperty(key){
……
};
} -
使用Firebug的“Timer”优化你的代码
快速而简单地让你知道你的代码执行效率。
-
保持读书的习惯
博客无法替代书籍,尤其是在吃饭时或是在床上。
选择一本好书放在你的床头,以下几本是我最喜欢的:
- Object-Oriented JavaScript
- JavaScript: The Good Parts
- Learning jQuery 1.3
- Learning JavaScript
通读它们,反复地。
-
自动触发的函数
直接运行的代码应该封装在一个自动触发的函数中,除了减少全局量之外,其他的函数还可以更加方便的调用。
(function doSomething(){
……
})(); -
原生代码永远比框架快速
类似于jQuery之类的框架可以加快开发速度,但是记住,它们的执行效率永远不会比书写良好的原生代码更高。
-
使用非原生的JSON解析器
尽管JavaScript2内置了原生的JSON解析器,但是仍然建议使用由JSON发明者Crockford编写的JSON解析器。
压缩后的此解析器小于2.5K,相关文档以及下载地址可以参考《JavaScript中的JSON》。
-
不再声明“language”属性
去掉script对象中陈旧的language属性。
天上人间是阳朔
photograph, 4 may, 2009
晚上八点多抵达两江机场,到达市区找好住处后,桂林的夜晚仍然五光十色。

桂林米粉品种很多,诸如“酸辣米粉”“叉烧米粉”等,最正宗的桂林米粉,当属“卤菜米粉”,而在众多卤菜之中,又以卤牛肉和卤“馄肝”(猪胰腺)最有特色,米粉还分为“榨粉”和“切粉”两类,从厨房拿到米粉后,客人还需要根据自己的口味添加包括香菜、葱花、蒜蓉、干辣椒、酸白菜等在内的各种配料,最后根据个人喜好,加入骨头汤,方成一碗地道的桂林米粉。品尝桂林米粉,一半在吃,另一半也许就是在吃之前的这些门道吧。

与五年前相比,街边“特价机票”“漓江船票”“桂林特产”的霓虹招牌倒是多了不少,摩托车司机们拉皮条的广告也比过往更直白,除此之外,目之所睹变化不大,沿着两江四湖走上一圈,不过一个小时,夜游桂林的精华尽在其中。



在这里要特别赞一下桂林的中山路。白天它是一条普通的六车道城市主干道,到了晚上,其中的三个车道就会搭起棚户,成为一条比正阳路更名副其实的步行街。尽管卖的东西没有什么特别的,但手拿一杯珍珠奶茶,在刚才还车水马龙的马路中央打望各色美女,的确是别处难得的体验。

阳朔县城里出现了很多在建或在售的楼盘,忽如一夜春风来地迅速将这一方山水裹挟入实践科学发展观推进城市大建设的历史大潮中。彩色喷绘的“做强优势产业壮大县域经济”硕大招牌下,有人用黑色喷漆在裸露的山石上无力地写下“PLEASE SAVE HERE”的大写英文。旁边几台搅拌机正隆隆做响,看样子这块石头本身都已划入开发商的红线内。泱泱大流,顺之则昌逆之则亡,你我不过萍水相逢沧海两粟,谁又救得了谁呢。


租上一辆自行车逛逛附近的乡村是一件非常惬意的事情。傍晚,游人散去,竹筏收工后,小孩跳入河中畅游,四周炊烟飘起,遇龙桥才像是个真正的仙境,以至于我在桥边发了一个小时的呆……



晚上九点终于回到酒店后的我得出一个天大的感悟:去程有多美,回程就有多远。


西街不是一条适合一个人逛的街,夜色妖娆钟灯红酒绿,外面世界有的,西街都有,实在是让人意兴阑珊。

第二天早上五点钟,从兴坪出发,徒步漓江,沿途峰回路转层峦叠嶂好一幅山水甲天下。相较桂林市区和阳朔县城,这里的村民同样很有生意头脑,他们会热情的招呼游客乘坐竹筏,但即使谢绝,仍然会很有兴致地用骄傲口吻为游客指路和介绍景点,若是碰上同样客气的客人,彼此之间非得三步一回首不可。


相比武夷山的九曲溪,漓江边上有更多适宜游水的浅滩,附近的山峰也多可攀爬。如果不是体力问题,仅仅乘坐游船游玩漓江会是一件不那么过瘾的事情。溯流而上,翻山涉水,好不自在。




桂林阳朔背包客旅游贴士
- 两江机场至市区依维柯中巴票价15元,中巴终点站火车站离市中心约1.5公里;
- 两江四湖无需门票,晚上11点景观灯关闭,10点50分前就熄灯的可能性更大;
- 桂林市区内景点学生证无任何优惠;
- 桂林市区内住宿方便,带热水标准间的招待所约50元;
- 桂林到阳朔巴士15元,尽管两地间有高速,但一般不走高速;
- 阳朔西街内住宿价格与市区基本一致,除西街外还有很多更便宜的住处;
- 租用自行车尤其是双人自行车务必考虑实际路况,如果准备安排超过2小时以上的自行车活动,山地自行车是最佳选择;
- 在阳朔按天包租一辆三轮车游玩也是不错的选择,价格约在50到100元一天;
- 徒步漓江的精华路段是从兴坪到杨堤,需要乘坐2次渡轮3过漓江,一半山路一半平地,全程步行耗时约5到10个小时;
- 冷水村渡口本地人1元外地人4元,此处是徒步必经之地;
- 老村口村到下龙村之间有全程唯一的岔路,此段注意沿河行进;
- 浪石至杨堤间的渡船2渡漓江,称为横水渡,每人16元,性价比非常低,建议从兴坪逆流向杨堤徒步,行至全家洲后乘坐竹筏至杨堤,每船价格约30到50元,路程约1小时;
- 杨堤码头定时有班车到阳朔,8元,全程约1小时,经停八队可中途下车乘坐过路大巴返回桂林;
- 阳朔全天开行至桂林班车,阳朔至柳州班车末班车为15:30。
西安是个大杂烩
photograph, 1 may, 2009
从成都到西安的火车上,一个在成都念书的小女孩用四川话无不怀念地告诉我说:西安比成都好耍太多咯!

一下火车便赶到陕西历史博物馆门前,加入了排队的长龙,一个小时后方得入馆,但馆内对这片先秦之地的详实展出,却让我足足花了三个小时,八百里秦川内外,上下五千年历史,尽在其中。

尽管“Made in China”已经成功地风靡全球,但当看到馆内精巧的唐代金属机械展品后,我仍然怀疑今天的我们还能不能做出三千年后让后人为之叫绝的工业产品。

九天阊阖十朝古都的西安,其本身就应该是一座天然的历史博物馆,但事实上:写着红色拆字的土灰色的六层楼房,绘有楼盘广告的围墙内的建筑工地,悬挂着各式牌匾的政府机关大院,间或的在十字路口处出现的玻璃幕墙大楼或所谓购物广场……街道与国内大多数城市相比并无二致。


一开始我还很好奇,为什么大小雁塔都在城墙外,在小雁塔下的西安博物院里方才得知,今天的西安城垣修筑始于明代,唐长安城早已毁于唐朝末年迁都洛阳之时,今天的大小雁塔便是当初仅存的遗迹,岿然独存的大小雁塔也许正好诠释了那句“万里江山万里尘,一朝天子一朝城”。

登上翻修彻底到没有一丝沧桑的城墙,默念着“骊宫高处入青云,仙乐风飘处处闻”,想象着“回头下望人寰处,不见长安见尘雾”的李隆基和杨玉怀……还会有多少故事将深埋在这朱雀门之下呢?西安是一座太遗憾的城市。


早餐油泼面,午饭羊肉泡馍,宵夜麻什,还有后来吃到的哨子面,西安的面食种类本身就已让人应接不暇,分量更是让我暗念“粒粒皆辛苦”——小份的份量就几乎是广州大碗云吞面的两倍……二十五一碗泡馍的定价看得出西安人实在是想赚钱,但还是不会赚钱,这就是所谓的民风淳朴吧。
西北人的爽朗正如他们的城市一样,方方正正,西安人不分男女老少在街边扭起秧歌的豪爽与干梆硬正的西安话如出一辙,背景里璀璨的安定门似乎又给这一幕增添了一屡别处没有的宽厚雍容。

及至回民街,热闹已经不足以形容此处的沸腾景象。柿饼、青海酸奶、酸梅汤、“镜饼”、枣子……当然烤肉是少不了的。

与大多数城市的夜市不同,鼓楼广场更像一个游乐园,即场的男女老少都像是春游的孩子般开心,套圈的,放风筝的,打气球的,晒月亮的,既有汉族也有回族,白皮肤黑皮肤黄皮肤……没有城管也没有交警更没有军队,这显然是一个缺乏管理的城市,但那却是我见过最和谐的一幕。


晃眼的白炽灯还有嘈杂的声浪,包括头顶黑色的天空在内,西安仿佛是一个巨大的游乐园,一切都让所有人兴奋。

在街的最末,一档生意冷清的摊位上摆放了无数个大大小小的仿制兵马俑,它们有的甚至还没来得及喷上金色油漆,这些表情木讷的兵士,即便被做成玩偶当街遭人批发,仍有一种质朴的力量让人感觉到他们的伟大。
西安咸阳背包客旅游贴士
- 西安咸阳机场距离西安市区接近50公里,大巴25元,包车约120元;
- 咸阳机场根据不同航空公司分A和B两个航站楼,其间有免费电瓶车;
- 陕西历史博物馆早上九点开馆,需要携身份证排队领取免费门票;
- 包括城墙(40元)和小雁塔(50元)在内的西安多处景点,包括大学在内的学生证可获半价优惠。
















