日期:2014-05-17  浏览次数:23025 次

谈谈Javascript那些操蛋的事(一)?
1. 永远不要写function _name(){…}的形式,要养成var _name=function(){}的习惯。
“Javascript中函数是头等公民”,意味着引擎对函数语句的优先处理,这样会导致你的程序很混乱,不仅如此,而且不同的浏览器引擎在处理函数语句的一些操作时,比如重写、apply调用、eval生成等等存在很大差异,如果你不想碰上这些潜在的危险,请养成良好的习惯,记住“Javascript中函数语句是头等公民”,永远不要写函数语句,要换成函数表达式或函数字面量,这样更能体现Javascript函数式编程风格---Lambda表达式。这个源自Scheme语言中函数可以当值赋值给变量的思想在Javascript中大放光彩,而且影响着Python、C++、C#、Java,看看Anders的代码,老赵的代码,原来大师是这样做的、信徒都是这样模仿的。呵呵,对于函数表达式(或函数字面量)我是好话说尽,道理讲绝,用不用随你了
2.一定要养成K&R风格。
无论你信不信,高手的代码都是K&R风格,实话实说,我本人是非常讨厌K&R风格,这是个编程风格问题,没有潜在的风险。如果真是如此,我大可不必如此鼓吹,事实上,形如
return
{
}
引擎会在return后自动插入一个分号,后果可想而知
这时候如果养成这样的习惯
  return{
  }
刚才那种潜在的风险就消除了。呵呵,好像可以少打一个换行符,为你节省些时间
3. 坚决不要遗漏“;”
在一些特定情况下你遗漏一个“;”不会出现风险,你的程序是正常的。但请你不要侥幸,当你洋洋洒洒上千行JS代码进行压缩时,你会发现总运行不起来,也许“;”就是这个罪魁祸首。呵呵,该加上“;”时一定要加上,这浪费不了你多长时间,不加上也节省不了你多长时间(但有时后果会很严重!)
4. 一定要记住这六大败类。
NaN 0 null “” undefined false  
不仅如此,还要懂得如何判定,当你考虑一个传入的参数时,这六大败类你是否都考虑了。当你完成一个完整无误、健壮的程序时,你偶然间遇到一个憋足的程序员,这个憋足的程序员又偶然间遇到憋足的IE,更绝的是又恰好遇到这个百年不遇的憋足属性,忽然间程序就这样崩溃了。你百思不得其解,最后费了九牛二虎之力终于把这个bug找出来,你会说“fuck,我少考虑了一种情况”。呵呵,Javascript程序员的嘴能不脏吗?
5. 要慎用递归调用
有的人说递归简洁、通俗易懂,而递归在不可读懂的代码中也发挥着重要作用。在Javascript中该怎么办?我建议最好不要用,除非在安全的前提下,递归特别容易解决问题时你可以尝试使用。一般而言,各种允许递归的语言把递归转化成循环处理,而Javscript中没这项优化,它直接当做函数调用处理的。函数嵌套调用要考虑中断处的现场记录与恢复,比相同功能的指令代码要耗时一些,更大的问题是引擎对嵌套调用的深度有所限制。当你遇到一个憋足的DOM树时,你用递归处理可能会使程序崩溃。
呵呵,递归是简洁的,但在Javascript中是耗时的,并存在一定风险,用不用随缘
6. 要牢记这些“站着茅厕不拉屎”的保留关键字
在进行Javascript语义API设计时,注意!不要和这些保留字争名子,就算争过了,兼容性也会让你死的难看。呵呵,的确,那些保留字是那么简洁、通俗、漂亮,但是你敢用吗?
7. 谨慎对待DOM的一切
Javascript是一门允许重写的语言,但不同的引擎在一些特殊场合都做了不同的限定,所以在进行故意重写时,你首先问问你重写的了吗?兼容性如何?在进行一些语义API设计时,要避免和DOM的属性名雷同。呵呵,总之,对待DOM属性名字要小心为甚!
8. 勤加“()”
Javascript有一个优点就是:你可以使用“||”和“&&”进行并联和串联求值,可以用“?:”简化条件语句,比如
  (e.offsetX||e.layerX)+x; (a+b)||c;a=b+((c.s>d)?1:0);
  (a&&a.b&&a.b.c)+(c.s||c.y) …
注意一定不要忘记加上“()”,在涉及“||”,“&&”,“?:”的运算符问题时,即使有些可以不加“()”,也要加上“()”,这是一个习惯问题,好的习惯可以让你从根本上杜绝忘记加“()”的可能性。呵呵,总之,不要认为可以不加“()”就不加“()”,突然间有一天某个时刻可以加“()”但你却不留神忘记加“()”时,你想找到错误都是困难的。
9. 谨慎对待“||”
使用“||”进行并联求值运算是Javascript的一大预言特色,例如
  e.x=_e.offsetX||_e.layerX
这时你考虑到_e.offsetX为0的情况没有?虽然有时不会出现问题,但大多数类似这样的并联运算得到的结果都是有风险的。呵呵,消灭此风险的方法就是对“||”运算要考虑周到!
10. 杜绝“==”,“!=”运算符
你是在进行比值吗?那么用“===”,“!==” ,而“==”,“!=”浏览器都说不清,你干吗还趟这趟浑水
11.谨记这个特例 NaN!==NaN,(NaN===NaN)为false
在“===”运算符上,NaN是一个特例,可见,不能过于相信(a===a)的结果!
12. 深思熟虑的对待嵌套定义函数问题。
这个问题说成闭包(cloure)更专业一些,什么是闭包?感觉周爱民的叙述恰如其分-----运行时创建的函数实例。闭包是Javascript中的瑞士军刀就像指针之于C语言。
首先,闭包在Javascript中具有很高的技巧性,例如以下形式
  var _o=(function(){
  var p1,p2;//…
  //…
  return {
   
  };
  })();
var _f=(function(){
  var p1,p2;//…
  //…
  return function(){
  //…
  };
 })();
闭包的特点是它们有自己的作用域权限,而且共享嵌套函数的成员数据,这种特性使它在模拟私有数据成员、静态成员、只读成员,完成单体设计,延迟性加载等等功能时发挥着重要作用。
当然,闭包的缺点也很多。这些都要从Javascript的设计说起,Javascript本身没有链接的机制,所有变量都要挂载到一个全局对象上,这个全局对象由引擎根据宿主环境生成,在浏览器环境下就是window对象。这很容易引发命名冲突问题,还好,Javascript明确的以函数划分作用域,但可惜的是存在块语法而不存在块作用域,这样一来函数就成为了划分作用域的唯一标准
Javascript中的闭包无论是在项目的战术细节上还是战略规划上都起着关键性作用,但是必须注意以下事项:
1. this和arguments的问题 2.循环中闭包对外层变量的引用问题 3.闭包带来的性能消耗和内存泄露
对于第一个问题,我们可以设定var that=this,arg=arguments;对于闭包中的this绑定问题,如果仅作为函数调用,那么很不幸,this被绑定到了window上
对于第二和问题,形如
  for(var i=0;i<n;i++){
  obj[i]=function(){
  //引用外界变量i
  alert(i);
  };
  }
这时候恐怕输出的都是n,注意可不全是n-1
 
我们有以下解决方案: