大连仟亿科技
客服中心
  • 电话
  • 电话咨询:0411-39943997
  • 手机
  • 手机咨询:15840979770
    手机咨询:13889672791
网络营销 >更多
您现在的位置:仟亿科技 > 新闻中心 > 常见问题

WEB开发中常见的编码错误

作者:billionnet 发布于:2012/11/30 16:51:19 点击量:

 我们在平时的web开发工作中,大多数程序员很少会关心细节问题,本文作者跨越多个语言,为大家总结了二十个常见的编码错误,并提供了很好的解决方案,供大家参考学习。

不管你现在的编程技能有多么的高超,曾经你也是个亦步亦趋,不断的学习的初学者。在编程这条曲折的道路上,我想你肯定犯过一些低级的错误、遇见过一些普通的编码陷阱。本文作者跨越多个语言,为大家总结了20条常规陷阱,并提供了解决方案。

JavaScript篇

1.不必要的DOM操作

例如下面这段代码:


  1. //anti-pattern
  2. for(vari=0;i<100;i++){
  3. varli=$("
  4. ").html("Thisislistitem#"+(i+1));
  5. $("#someUL").append(li);
  6. }

这段代码对DOM进行了100次修改,并且创建了100个不必要的jQuery对象。正确的做法是使用一个文档片段,或者创建一个字符串,把100个

  • 元素赋给该字符串。然后附加到HTML中。这样就只需运行DOM一次,代码如下:

    
    
    1. varliststring="";
    2. for(vari=100;i>0;i--){
    3. liststring+="
    4. Thisislistitem#"+(99-i);
    5. }
    6. document.getElementById("someUL").innerHTML(liststring);

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

    
    
    1. varliststring="
    2. "
    3. varlis=[];
    4. for(vari=100;i>0;i--){
    5. lis.push("Thisislistitem#"+(99-i));
    6. }
    7. liststring+=lis.join("
    8. ")+"
    9. ";
    10. document.getElementById("someUL").innerHTML(liststring);

    这是在JavaScript创建重复HTML最快最简单的方法,无需使用模板库或框架。

    2.不一致的变量名和函数名

    这个问题是非常重要的,尤其当你在别人的代码上工作时,一定要保持标识符(变量名和函数名)一致,例如下面这段代码:

    
    
    1. varfoo="bar";
    2. varplant="green";
    3. varcar="red";

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

    下面是对函数的命名:

    
    
    1. functionsubtractFive(number){
    2. returnnumber-5;
    3. }

    语法结构清晰并且能起到解释性功能。

    例如想要对给定的数字加5,仍采用上述命名模式,比如:

    
    
    1. functionaddFive(number){
    2. returnnumber+5;
    3. }

    有时,你会根据返回值命名,例如该函数要返回一个HTML字符串,那么可以命名为getTweetHTML(),如果函数只是做一些操作,无需返回值,那么可以在前面加一个do前缀。例如doFetchTweets()。

    构造函数通常会遵循类原则,大写第一个字母:

    
    
    1. functionDog(color){
    2. this.color=color;
    3. }

    命名应带有描述性,比如操作型的函数在前面加do,另外要具备可读性和提示性。

    3.在for...Loops中使用hasOwnProperty()方法

    JavaScript数组是没有关联的,可以把它当做哈希表,使用循环来遍历对象属性:

    
    
    1. for(varpropinsomeObject){
    2. alert(someObject[prop]);//alert'svalueofproperty
    3. }

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

    
    
    1. for(varpropinsomeObject){
    2. if(someObject.hasOwnProperty(prop)){
    3. alert(someObject[prop]);//alert'svalueofproperty
    4. }
    5. }

    4.比较布尔值

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

    
    
    1. if(foo==true){
    2. //dosomethingfortrue
    3. }else{
    4. //dosomethingforfalse
    5. }

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

    
    
    1. if(foo){
    2. //dosomethingfortrue
    3. }else{
    4. //dosomethingforfalse
    5. }

    又或者这样写:

    
    
    1. if(!foo){
    2. //dosomethingiffooisfalse
    3. }else{
    4. //dosomethingiffooistrue
    5. }

    5.事件绑定

    在JavaScript中,事件是个复杂的问题。事件冒泡(event bubbling)和委托正在取代内联事件(inline onclick)操作(一些特殊的“初始页”除外)。

    假设你有一个图片网格,需要启动一个modal lightbox窗口。千万不要采取下面的做法,示例采用的是jQuery,如果你使用相似的库或者其他,冒泡机制也同样适合传统的JavaScript。

    相关的HTML代码:

    
    
    1. ...
  • 不好的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. returnfoo.toString()!==""?true:false;
    
    
    1. //php
    2. return(something())?true:false;

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

    
    
    1. //javascript
    2. returnfoo.toString()!=="";
    
    
    1. //php
    2. returnsomething();

    PHP篇

    7.适当的时候使用三元操作

    If...else语句是大多数语言的重要组成部分。但有些简单的事情,比如根据条件进行赋值,你很有可能会这样写:

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

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

    
    
    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='Therewasanerrorcreatingthethumbnail.';
    11. }
    12. }
    13. else
    14. {
    15. $error_message='Therewasanerroruploadingtheimage.';
    16. }
    17. }
    18. else
    19. {
    20. $error_message=$this->form_validation->error_string();
    21. }
    22. //Showerrormessages
    23. if($error_message!==null)
    24. {
    25. $this->load->view('form',array(
    26. 'error'=>$error_message,
    27. ));
    28. }
    29. //Savethepage
    30. else
    31. {
    32. $some_data['image']=$image['file_name'];
    33. $this->some_model->save($some_data);
    34. }

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

    
    
    1. try
    2. {
    3. if(!$this->form_validation->run())
    4. {
    5. thrownewException($this->form_validation->error_string());
    6. }
    7. if(!$this->upload->do_upload())
    8. {
    9. thrownewException('Therewasanerroruploadingtheimage.');
    10. }
    11. $image=$this->upload->get_info();
    12. if(!$this->image->create_thumbnail($image['file_name'],300,150))
    13. {
    14. thrownewException('Therewasanerrorcreatingthethumbnail.');
    15. }
    16. }
    17. //Showerrormessages
    18. catch(Exception$e)
    19. {
    20. $this->load->view('form',array(
    21. 'error'=>$e->getMessage(),
    22. ));
    23. //Stopmethodexecutionwithreturn,oruseexit
    24. return;
    25. }
    26. //Gotthisfar,mustnothaveanytrouble
    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. classCustomExceptionextendsException{}

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

    10.Use Guard Clauses

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

    
    
    1. functionsomeFunction($param){
    2. if($param=='OK'){
    3. $this->doSomething();
    4. returntrue;
    5. }else{
    6. returnfalse;
    7. }
    8. }

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

    
    
    1. functionsomeFunction($param){
    2. if($param!='OK')returnfalse;
    3. $this->doSomething();
    4. returntrue;
    5. }

    11.使用While进行简单的迭代

    使用for进行循环是很常见的事情:

    
    
    1. for(vari=0;i
    2. ...
    3. }

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

    
    
    1. vari=x;
    2. while(i--){
    3. ...
    4. }

    12.保持方法可维护性

    让我们来看一下这个方法:

    
    
    1. classSomeClass{
    2. functionmonsterMethod(){
    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. }
    22. }

    再看如下代码:

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

    对比两段代码,第二段代码非常简洁、可读和可维护。

    13.避免深层嵌套

    太多层的嵌套会让代码很难阅读、理解和维护。看看下面的代码:

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

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

    
    
    1. functiondoSomething(){
    2. if(!$someCondition){
    3. returnfalse;
    4. }
    5. if(!$someOtherCondition){
    6. returnfalse;
    7. }
    8. if($yetSomeOtherCondition){
    9. doSomethingSpecial();
    10. }
    11. doSomethingElse();
    12. }

    相对于前面的代码,这段代码简洁了很多,并且所实现的功能也是一样的。

    当你在if里面使用嵌套,请仔细检查代码,里面可能同时执行多个方法,例如下面这段代码:

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

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

    
    
    1. functionsomeFunc(){
    2. if($oneThing){
    3. $this->doSomething();
    4. $this->doAnotherThing($anotherThing);
    5. }
    6. }
    7. privatedoAnotherThing($anotherThing){
    8. if($anotherThing)
    9. $this->doSomethingElse();
    10. }

    14.避免使用匿名数字和字符串(Avoid Magic Numbers and Strings)

    使用匿名数字和字符串是有害无益的,在代码里定义需要使用的变量和常量。比如下面这段代码:

    
    
    1. functionsomeFunct(){
    2. $this->order->set(23);
    3. $this->order->addProduct('superComputer');
    4. $this->shoppingList->add('superComputer');
    5. }

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

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

    可能会有人认为,一些无意义的变量尽量少定义,虽然它们对性能的影响是微不足道的。但可读性永远处于优先地位。请记住:不要随便优化性能,除非你知道为什么。

    15.使用Built-in数组函数

    使用built-in函数来代替foreach()

    差的代码:

    
    
    1. foreach(&$myArrayas$key=>$element){
    2. if($element>5)unset($myArray[$key]);
    3. }

    改进后的代码:

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

    PHP里面提供了许多数组方法。起初会混淆,但是试着花时间好好学学它们。

    16.不要过度使用变量

    大家在开发过程中很容易使用变量,但请记住,变量是需要存储在内存中的。看下面这段代码:

    
    
    1. publicfunctionget_posts(){
    2. $query=$this->db->get('posts');
    3. $result=$query->result();
    4. return$result;
    5. }

    $result变量其实是不需要的。

    
    
    1. publicfunctionget_posts(){
    2. $query=$this->db->get('posts');
    3. return$query->result();
    4. }

    虽然这些差别都是微不足道的,但对于养成良好的编码习惯还是 很重要的。

    通用篇

    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保持。

    结论

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



    本文地址:http://www.billionnet.net/c/2012112336.html
    分享到:


    【刷新页面】【加入收藏】【打印此文】 【关闭窗口】
    评论加载中...
    内容:
    评论者: 验证码:
      

    Copyright@ 2011-2017 版权所有:大连仟亿科技有限公司 辽ICP备11013762-1号   google网站地图   百度网站地图   网站地图

    公司地址:大连市沙河口区中山路692号辰熙星海国际2215 客服电话:0411-39943997 QQ:2088827823 42286563

    法律声明:未经许可,任何模仿本站模板、转载本站内容等行为者,本站保留追究其法律责任的权利! 隐私权政策声明