[转帖]20条常见的编码陷阱 你中枪了没?_Android, Python及开发编程讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  Android, Python及开发编程讨论区 »
总帖数
2
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 3257 | 回复: 1   主题: [转帖]20条常见的编码陷阱 你中枪了没?        下一篇 
zhou
注册用户
等级:中校
经验:2210
发帖:125
精华:6
注册:2012-11-19
状态:离线
发送短消息息给zhou 加好友    发送短消息息给zhou 发消息
发表于: IP:您无权察看 2012-11-22 11:09:30 | [全部帖] [楼主帖] 楼主

20条常见的编码陷阱 你中枪了没?   JavaScriptPythonPHP编程语言 摘要:在平时的编程工作中,大多数程序员很少会关心细节问题,本文作者跨越多个语言,为大家总结了20条常规陷阱,并提供了很好的解决方案,供大家参考学习。
不管你现在的编程技能有多么的高超,曾经你也是个亦步亦趋,不断的学习的初学者。在编程这条曲折的道路上,我想你肯定犯过一些低级的错误、遇见过一些普通的编码陷阱。本文作者跨越多个语言,为大家总结了20条常规陷阱,并提供了解决方案。
JavaScript篇
1.不必要的DOM操作
例如下面这段代码:

  1. // anti-pattern  
  2. for (var i = 0; i < 100; i++){  
  3.  var li = ("<li>").html("This is list item #" + (i+1));  
  4.  ("#someUL").append(li);  


这段代码对DOM进行了100次修改,并且创建了100个不必要的jQuery对象。正确的做法是使用一个文档片段,或者创建一个字符串,把100个<li>元素赋给该字符串。然后附加到HTML中。这样就只需运行DOM一次,代码如下:

  1. var liststring = "";  
  2. for (var i = 100; i > 0; i--){  
  3.  liststring += "<li>This is list item #" + (99- i);  
  4. }  
  5. document.getElementById("someUL").innerHTML(liststring); 


正如上面所描述的一样,下面再提供一个方式,使用数组:

  1. var liststring = "<li>" 
  2. var lis = [];  
  3. for (var i = 100; i > 0; i--){  
  4.  lis.push("This is list item #" + (99- i));  
  5. }  
  6. liststring += lis.join("</li><li>") + "</li>";  
  7. document.getElementById("someUL").innerHTML(liststring); 


这是在JavaScript创建重复HTML最快最简单的方法,无需使用模板库或框架。
2.不一致的变量名和函数名
这个问题是非常重要的,尤其当你在别人的代码上工作时,一定要保持标识符(变量名和函数名)一致,例如下面这段代码:

  1. var foo = "bar";  
  2. var plant = "green";  
  3. var car = "red"; 


通常,人们并不会设置变量名叫Something,这涉及到命名规则问题,命名应清晰明了,一目了然。很多编程语言地变量命名都使用大写。
下面是对函数的命名:

  1. function subtractFive(number){  
  2.  return number - 5;  


语法结构清晰并且能起到解释性功能。
例如想要对给定的数字加5,仍采用上述命名模式,比如:

  1. function addFive(number){  
  2.  return number + 5;  


有时,你会根据返回值命名,例如该函数要返回一个HTML字符串,那么可以命名为getTweetHTML(),如果函数只是做一些操作,无需返回值,那么可以在前面加一个do前缀。例如doFetchTweets()。
构造函数通常会遵循类原则,大写第一个字母:

  1. function Dog(color){  
  2.  this.color = color;  


命名应带有描述性,比如操作型的函数在前面加do,另外要具备可读性和提示性。
3.在for...Loops中使用hasOwnProperty()方法
JavaScript数组是没有关联的,可以把它当做哈希表,使用循环来遍历对象属性:

  1. for (var prop in someObject) {  
  2.  alert(someObject[prop]); // alert's value of property  


然而,存在的问题是for...in loop是在对象属性链上遍历每个枚举类型的属性,如果你只想使用对象实际拥有的属性,这可能有问题的。那怎么解决呢?你可以使用hasOwnProperty()方法。代码如下:

  1. for (var prop in someObject) {  
  2.  if (someObject.hasOwnProperty(prop)) {  
  3.  alert(someObject[prop]); // alert's value of property  
  4.  }  


4.比较布尔值
把布尔值作为条件进行比较,其实这是在浪费电脑的计算时间。看下面这个例子吧:

  1. if (foo == true) {  
  2.  // do something for true  
  3. } else {  
  4.  // do something for false  


其实foo==true这个比较完全是多余的,因为foo已经是布尔类型。直接这样写就行:

  1. if (foo) {  
  2.  // do something for true  
  3. } else {  
  4.  // do something for false  


又或者这样写:

  1. if (!foo) {  
  2.  // do something if foo is false  
  3. } else {  
  4.  // do something if foo is true  


5.事件绑定
在JavaScript中,事件是个复杂的问题。事件冒泡(event bubbling)和委托正在取代内联事件(inline onclick)操作(一些特殊的“初始页”除外)。
假设你有一个图片网格,需要启动一个modal lightbox窗口。千万不要采取下面的做法,示例采用的是jQuery,如果你使用相似的库或者其他,冒泡机制也同样适合传统的JavaScript。
相关的HTML代码:

  1. <div id="grid-container"> 
  2.    <a href="someimage.jpg"><img src="someimage-thumb.jpg"></a> 
  3.    <a href="someimage.jpg"><img src="someimage-thumb.jpg"></a> 
  4.    <a href="someimage.jpg"><img src="someimage-thumb.jpg"></a> 
  5.    ...  
  6. </div> 


不好的JavaScript写法:

  1. ('a').on('click', function() {  
  2.  callLightbox(this);  
  3. }); 


这段代码假设调用lightbox,里面传递一个anchor元素并且引用全屏图片。与其绑定每个anchor元素还不如直接使用#grid-container元素。

  1. ("#grid-container").on("click", "a", function(event) {  
  2.  callLightbox(event.target);  
  3. }); 


在这段代码中,this和event.target都表示anchor元素。同样你也可以在任何父元素上使用。只要保证所定义的元素是事件目标就行(event's target)。
6.避免三元冗余
在JavaScript和PHP中,过度使用三元语句是很常见的事情:

  1. // javascript  
  2. return foo.toString() !== "" ? true : false; 
  1. // php  
  2. return (something()) ? true : false; 


条件判断的返回值永远只有false和true,言外之意就是你无需把true和false显示添加到三元运算中。相反,你只需简单的返回条件:

  1. // javascript  
  2. return foo.toString() !== ""; 
  1. // php  
  2. return something(); 


PHP篇
7.适当的时候使用三元操作
If...else语句是大多数语言的重要组成部分。但有些简单的事情,比如根据条件进行赋值,你很有可能会这样写:

  1. if (greeting)  
  2. {  
  3.  post->message = 'Hello';  
  4. }  
  5. else 
  6. {  
  7.  post->message = 'Goodbye';  


其实使用三元操作只需一行代码就可以搞定,并保持了良好的可读性:

  1. post->message = greeting ? 'Hello' : 'Goodbye'; 


8.抛出异常,而不是采用盗梦空间式的嵌套(Inception-Style Nesting)
多层次的嵌套是丑陋的、难以维护和不可读的。下面的代码是个简单的例子,但是随着时间的推移会变得更糟:

  1. // anti-pattern  
  2. error_message = null;  
  3. if (this->form_validation->run())  
  4. {  
  5.  if (this->upload->do_upload())  
  6.  {  
  7.  image = this->upload->get_info();  
  8.  if ( ! this->image->create_thumbnail(image['file_name'], 300, 150))  
  9.  {  
  10.  error_message = 'There was an error creating the thumbnail.';  
  11.  }  
  12.  }  
  13.  else 
  14.  {  
  15.  error_message = 'There was an error uploading the image.';  
  16.  }  
  17. }  
  18. else 
  19. {  
  20.  error_message = this->form_validation->error_string();  
  21. }  
  22. // Show error messages  
  23. if (error_message !== null)  
  24. {  
  25.  this->load->view('form', array(  
  26.  'error' => error_message,  
  27.  ));  
  28. }  
  29. // Save the page  
  30. else 
  31. {  
  32.  some_data['image'] = image['file_name'];  
  33.  this->some_model->save(some_data);  


如此凌乱的代码,是否该整理下呢。建议大家使用异常这个清洁剂:

  1. try  
  2. {  
  3.  if ( ! this->form_validation->run())  
  4.  {  
  5.  throw new Exception(this->form_validation->error_string());  
  6.  }  
  7.  if ( ! this->upload->do_upload())  
  8.  {  
  9.  throw new Exception('There was an error uploading the image.');  
  10.  }  
  11.  image = this->upload->get_info();  
  12.  if ( ! this->image->create_thumbnail(image['file_name'], 300, 150))  
  13.  {  
  14.  throw new Exception('There was an error creating the thumbnail.');  
  15.  }  
  16. }  
  17. // Show error messages  
  18. catch (Exception e)  
  19. {  
  20.  this->load->view('form', array(  
  21.  'error' => e->getMessage(),  
  22.  ));  
  23.  // Stop method execution with return, or use exit  
  24.  return;  
  25. }  
  26. // Got this far, must not have any trouble  
  27. some_data['image'] = image['file_name'];  
  28. this->some_model->save(some_data); 


虽然代码行数并未改变,但它拥有更好的可维护性和可读性。尽量保持代码简单。
9.False——Happy方法
Ruby或Python开发者常常关注一些微小的异常,这是相当不错的事情。如果有地方出错就会抛出异常并且你会立即知道问题所在。
在PHP中,特别是使用比较老的框架,如CodeIgniter,与抛出异常相比,它仅仅返回一个flase值,并且把错误字符串分配给其他一些属性。这就驱使你使用get_error()方法。
Exception-happy远远好于false-happy。如果代码里面存在错误(例如不能连上S3下载图片,或者值为空等),然后抛出一个异常,你也可以通过继承Exception类来抛出特定的异常类型,例如:

  1. class CustomException extends Exception {} 


抛出自定义类型异常会让调试变得更加容易。

 10.Use Guard Clauses


使用if语句控制函数或方法的执行路径是很常见的事情,如果if条件为true就执行if里面的代码,否则就执行else里面的代码。例如下面这段代码:

  1. function someFunction(param) {  
  2.  if (param == 'OK') {  
  3.  this->doSomething();  
  4.  return true;  
  5.  } else {  
  6.  return false;  
  7.  }  


这是很常见的意大利面条式的代码,通过转换条件对上述代码进行优化,不仅可以增加其可读性,看起来还会更加简单,如下:

  1. function someFunction(param) {  
  2.  if (param != 'OK') return false;  
  3.  this->doSomething();  
  4.  return true;  


11.使用While进行简单的迭代
使用for进行循环是很常见的事情:

  1. for (var i = 0; i < x; i++) {  
  2.  ...  


当然,for循环也有许多优势,但是对于一些的循环,使用while或许会更好:

  1. var i = x;  
  2. while (i--) {  
  3.  ...  


12.保持方法可维护性
让我们来看一下这个方法:

  1. class SomeClass {  
  2.  function monsterMethod() {  
  3.  if(weArePilots) {  
  4.  this->goAndDressUp();  
  5.  this->washYourTeeth();  
  6.  this->cleanYourWeapon();  
  7.  this->takeYourHelmet();  
  8.  if(this->helmetDoesNotFit())  
  9.  this->takeAHat();  
  10.  else 
  11.  this->installHelmet();  
  12.  this->chekcYourKnife();  
  13.  if(this->myAirplain() == "F22")  
  14.  this->goToArmyAirport();  
  15.  else 
  16.  this->goToCivilianAirport();  
  17.  this->aim();  
  18.  this->prepare();  
  19.  this->fire();  
  20.  }  
  21.  }  


再看如下代码:

  1. class SomeClass {  
  2.  function monsterMethod() {  
  3.  if(weArePilots) {  
  4.  this->prepareYourself();  
  5.  this->tryHelmet();  
  6.  this->findYourAirport();  
  7.  this->fightEnemy();  
  8.  }  
  9.  }  
  10.  private function prepareYourself() {  
  11.  this->goAndDressUp();  
  12.  this->washYourTeeth();  
  13.  this->cleanYourWeapon();  
  14.  this->chekcYourKnife();  
  15.  }  
  16.  private function tryHelmet() {  
  17.  this->takeYourHelmet();  
  18.  if(this->helmetDoesNotFit())  
  19.  this->takeAHat();  
  20.  else 
  21.  this->installHelmet();  
  22.  }  
  23.  private function findYourAirport() {  
  24.  if(this->myAirplain() == "F22")  
  25.  this->goToArmyAirport();  
  26.  else 
  27.  this->goToCivilianAirport();  
  28.  }  
  29.  private function fightEnemy() {  
  30.  this->aim();  
  31.  this->prepare();  
  32.  this->fire();  
  33.  }  


对比两段代码,第二段代码更加简洁、可读和可维护。
13.避免深层嵌套
太多层的嵌套会让代码很难阅读、理解和维护。看看下面的代码:

  1. function doSomething() {  
  2.  if (someCondition) {  
  3.  if (someOtherCondition) {  
  4.  if (yetSomeOtherCondition) {  
  5.  doSomethingSpecial();  
  6.  }  
  7.  doSomethingElse();  
  8.  }  
  9.  }  


条件里面又嵌套多个条件,通过转换条件,我们对代码进行了调整:

  1. function doSomething() {  
  2.  if (!someCondition) {  
  3.  return false;  
  4.  }  
  5.  if (!someOtherCondition) {  
  6.  return false;  
  7.  }  
  8.  if (yetSomeOtherCondition) {  
  9.  doSomethingSpecial();  
  10.  }  
  11.  doSomethingElse();  
  12. }  


相对于前面的代码,这段代码简洁了很多,并且所实现的功能也是一样的。
当你在if里面使用嵌套,请仔细检查代码,里面可能同时执行多个方法,例如下面这段代码:

  1. function someFunc() {  
  2.  if(oneThing) {  
  3.  this->doSomething();  
  4.  if(anotherThing)  
  5.  this->doSomethingElse();  
  6.  }  


这种情况下,可以把嵌套代码提取出来:

  1. function someFunc() {  
  2.  if(oneThing) {  
  3.  this->doSomething();  
  4.  this->doAnotherThing(anotherThing);  
  5.  }  
  6. }  
  7. private doAnotherThing(anotherThing) {  
  8.  if(anotherThing)  
  9.  this->doSomethingElse();  


14.避免使用匿名数字和字符串(Avoid Magic Numbers and Strings)
使用匿名数字和字符串是有害无益的,在代码里定义需要使用的变量和常量。比如下面这段代码:

  1. function someFunct() {  
  2.  this->order->set(23);  
  3.  this->order->addProduct('superComputer');  
  4.  this->shoppingList->add('superComputer');  


给23和“superComputer”赋予相应意义的变量名:

  1. function someFunct() {  
  2.  orderId = 23;  
  3.  selectedProductName = 'superComputer';  
  4.  this->order->set(orderId);  
  5.  this->order->addProduct(selectedProductName);  
  6.  this->shoppingList->add(selectedProductName);  


可能会有人认为,一些无意义的变量尽量少定义,虽然它们对性能的影响是微不足道的。但可读性永远处于优先地位。请记住:不要随便优化性能,除非你知道为什么。
15.使用Built-in数组函数
使用built-in函数来代替foreach()
差的代码:

  1. foreach (&myArray as key =>element) {  
  2.  if (element > 5) unset (myArray[key]);  


改进后的代码:

  1. myArray = array_filter(myArray, function (element) { return element <= 5;});  


PHP里面提供了许多数组方法。起初会混淆,但是试着花时间好好学学它们。
16.不要过度使用变量
大家在开发过程中很容易使用变量,但请记住,变量是需要存储在内存中的。看下面这段代码:

  1. public function get_posts() {  
  2.  query = this->db->get('posts');  
  3.  result = query->result();  
  4.  return result;  


result变量其实是不需要的。

  1. public function get_posts() {  
  2.  query = this->db->get('posts');  
  3.  return query->result();  


虽然这些差别都是微不足道的,但对于养成良好的编码习惯还是 很重要的。
通用篇
17.依赖数据库引擎
使用数据库来专门处理数据会让你的程序更高效。
例如,在大多数情况下,你可以避免冗余的数据查询。大多数的plug-and-play用户管理脚本在用户注册时都使用了两次数据查询:先检查用户名/邮件是否存在,另外再把用户信息插入到数据库中。一个比较好的做法是在数据库中设置username字段为UNIQUE,然后你可以利用本地的MySQL函数来检查用户名是否存在,然后添加进去。
18.正确命名变量
使用x、y、z命名变量的时代已经结束(除非是处理一个坐标系统)。变量是你逻辑代码的重要组成部分。不想键入长名字吗?获取一个好的IDE吧,使用IDE只需一眨眼的功夫就可以完成变量命名。
19.方法表示动作
见名知意,看到方法名字就知道它执行了哪些动作。使用一个短的,但具有描述性的范围命名(例如:public methods即可这样命名);使用一个长的名字,并且可以更加详细的描述(例如:定义private/protected methods)。这样会让你的代码更加可读可写。
当然也要避免用非英语来进行命名。例如使用“做些什麼()”或者делатьчтото()命名,简直是糟透了的命名。对于其他程序员来说,真的很难理解。尤其是在一个团队里,请记住,让你命名更加规范些吧!
20.结构的定义
最后,我们来说一下代码结构,从可读性和可维护性来讲,代码结构也是相当重要的,下面我们从两方面来讲:

  • 首行缩进4字节或2个标签宽度。
  • 设置合理的线宽(line-width)并且保持。一行只有40个字节?我们已经不是70年代的人了。一行限制在120个字节,并且在屏幕上放一个标签,并且驱使IDE保持。

结论
发生错误不要紧,关键是要总结错误,并且从中吸取教训,只有不断总结和学习,才能让你的编程之路走的更远。



赞(0)    操作        顶端 
zhou
注册用户
等级:中校
经验:2210
发帖:125
精华:6
注册:2012-11-19
状态:离线
发送短消息息给zhou 加好友    发送短消息息给zhou 发消息
发表于: IP:您无权察看 2012-11-22 11:10:14 | [全部帖] [楼主帖] 2  楼




赞(0)    操作        顶端 
总帖数
2
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论