天天看点

javaScript 编程风格命名语句和表达式变量函数和运算符

    "编程风格"的选择不应该基于个人爱好、熟悉程度、打字工作量等因素,而要考虑如何尽量使代码清晰易读、减少出错。你选择的,不是你喜欢的风格,而是一种能够清晰表达你的意图的风格。这一点,对于Javascript这种语法自由度很高、设计不完全成熟的语言尤其重要。

    程序员固然可以自由选择编程风格,但是好的编程风格有助于写出质量更高、错误更少、更易于维护的程序。下面以点概面,通过一些实际例子来简要概述一下好的编程风格

命名

  JavaScript语言的核心ECMAScript,遵照了驼峰是大小写:即命名法是由小写字母开始的,后续每个单词首字母都大写

  变量和函数的命名:变量名应该总是遵循驼峰大小写命名法,并且明明前缀是个名词;函数也是驼峰式命名(pascal Case),但是前缀应当是个动词。这样便于区分普通变量和函数变量。同时要注意,不要取一些毫无意义的名词(除了在循环中经常出现的i,j,k..),注入foo,bar,tmp之类随便拿来用的名字,如果不看上下文实在不好理解变量的本来目的。

//好的写法
  var count = 10;
  var myName = 'feng';
  var found = true;

  function getName() {
    return myName;
  }
  
  //不好的写法
  var getCount = 10;//看起来像函数
  var isFound = 10;//你是不是经常这么用
  //看起来像变量
  function theName() {
    return myName;
  }
           

  常量的命名:很长一段时间JavaScript中并没有真正意义上的常量,但是这并不能阻止开发者将变量用作常量。为了区分普通变量和常量,参考C语言,一种约定应运而生:使用大写字母和下划线来命名,下划线用于分隔单词。  

var MAX_COUNT = 10;
var URL = "http://m.jinhui365.com";

if(count < MAX_COUNT){
  doSomething();
}
           

  构造函数的命名:JavaScript中,构造函数只不过是前面冠以new预算符的函数,用来创建对象,上文提到过普通函数的命名采用的驼峰式。这里,构造函数的命名法也采用驼峰式,只不过是大驼峰,用来与普通函数做区分。大函数指在小驼峰基础上,将第一个字符替换成大写如(Pascal Case),还有构造函数的命名也常常是名词。所以,按照我们的“约定”,如果你看到大驼峰命名的函数名是名词,但是没有构造函数的话,肯定能瞬间定位到问题

function Person(name) {
  this.name = name;
}


var me = Person("feng");// new Person()
           

  案例一:重构一个代码风格混乱的功能函数:有一个需求,通过一系列toggle显示的折叠块显示内容。后台传来的字段为如下格式

[{"title":"投资目的","content":"”茅台增值回购351215”是以500ml 瓶装53°飞天茅台酒为标的,在贵州白酒交易所平台挂牌,并通过金汇平台进行直销的系列酒产品。"},
 "title":"提酒优势","content":"每个名义周期开始起5日到结束前5日之间都可以提酒。认购后,无论茅台酒市场价格如何变动,持有到期,您都将获得约定回报。",
"title":"转让优势","content":"我是转让规则"]
           

实现如下效果:每个{}中的内容作为一条信息:title作为标题,content作为描述文字;初始时只显示标题;点击任何一个title,展示对应的content;点击其他title则关闭当前content,展开另一个content;再次点击当前content,则只隐藏当前content

javaScript 编程风格命名语句和表达式变量函数和运算符

  实现代码如下,首先是html代码

<!--遍历explain数组-->
  <% for(var i = 0; i < explain.length; i++) { %>
    <div>
      <!--每个{}中的title:包含文字和右侧的箭头(箭头会随折叠变动防线)-->
      <div id="explain-title-<%= i %>" οnclick="togg(<%= i%>)">
        <div style="float: left;"><%= explain[i].title %></div>
        <span  class="btn_gd"></span>
      </div>
      <!--每个{}中的content-->
      <div id="explain-content-<%= i %>">
          <%- explain[i].content %>
      </div>
    </div>
  <% } %>
           

  下面看一下javaScript代码。主要的逻辑就是先将所有的content隐藏。当所有的content都关闭时,点击title则展示当前对应的content,设置temp为当前索引I;如果点击content时,如果不是所有的content都关闭则进行判断,当前的索引i是否等于temp,即点击的是否是当前的title,如果是当前的title则只进行关闭操作,如果点击的不是当前的title,则意味着点击的是一个新的title,则关闭上一个,打开新的content;

  有两个缺点:1 变量命名不规范,含义不明确 2.重复性代码过多

<script>
  var flag=true;
  var temp;
  function togg(i) {
    var target = '#explain-content-' + i;
    var target_title ='#explain-title-' + i;
    var old_target_title ='#explain-title-' + temp;
    if(flag){
      $('.explain-content').hide();
      $(target_title).removeClass('bottom-border')
      $(target_title).find('span').attr('class','btn_gu')
      $(target).show();
      flag=false;
      temp=i;
    }else{
      if(temp == i){
        $('.explain-content').hide();
        $(old_target_title).addClass('bottom-border')
        $(old_target_title).find('span').attr('class','btn_gd')
        flag=true;
      }else{
        var new_target = '#explain-content-' + i;
        var new_target_title = '#explain-title-' + i;
        $('.explain-content').hide();
        $(old_target_title).addClass('bottom-border')
        $(old_target_title).find('span').attr('class','btn_gd')
        $(new_target_title).removeClass('bottom-border')
        $(new_target_title).find('span').attr('class','btn_gu')
        $(new_target).show();
        temp=i;
        flag=false;
      }
    }
  }
</script>
           

  然后看一下经过调整之后的代码

  1.首先用currentOpened 和allHasClosed来替换掉意义模糊的temp和flag;

  2.将逻辑进行拆分:打开第i个,关闭第i个,分别封装成不同的函数

<script type="text/javascript">
  function open(i) {
    var target = '#explain-content-' + i;
    var target_title = '#explain-title-' + i;
    $(target_title).removeClass('bottom-border')
    $(target_title).find('span').attr('class', 'btn_gu')
    $(target).show();
    currentOpened = i;
  }
  function close(i) {
    var target_title = '#explain-title-' + i;
    $(target_title).addClass('bottom-border')
    $(target_title).find('span').attr('class', 'btn_gd')
    $('.explain-content').hide();
  }

  var currentOpened;
  var allHasClosed = true;

  function togg(curentClick) {
    if (allHasClosed) {
      open(curentClick);
      allHasClosed = false;
    } else {
      close(currentOpened);
      if (currentOpened == curentClick) {
        allHasClosed = true;
      } else {
        open(curentClick);
      }
    }
  }

</script>
           

语句和表达式

  花括号的对齐:分为两种:第一种风格是将花括号放置在块语句中第一句代码的末尾,比如

if (condition) {
    doSomething();
  } else {
    doSomethingElse();
  }
           

  第二种风格是将做花括号放置在块语句首航的下一行,比如

  if (condition) 

  {

    doSomething();

  } 

  else 

  {

    doSomethingElse();

  }

  推荐第一种对齐方式,因为不仅代码看起来紧凑,同时也会避免JavaScript自动给行尾添加‘;’带来的错误,比如下面的代码采用第二种对齐方式,原意是返回一个对象,实际上返回的是一个undefined值

return 
{
  key : value;
};
           

  因为javascript实际上会给return后面添加分号,使一个return语句变成了reuturn;

  不要省略行尾分号;就这么简单,而且是永远不要

  避免使用with语句:无法辨别出with代码块中的属性的归属,同时javascript引擎和压缩工具无法对这段代码进行优化

  for 与 for-in循环:乍一看很相似,但是却有着完全不同的用法。

  传统的fo循环用于遍历数组成员,比如

var values = [ 0, 1, 2, 3, 4, 5],
      i,len;
  for (i=0, len=values.length; i < len; i++) {
    alert(values[i]);
  }  
           

  而for-in循环是用来遍历对象属性的,普遍禁止用来便利数组。不用定义任何控制条件,循环会有条不紊的遍历每个对象属性,并返回属性名而不是值,比如:

var prop;
for (prop in object) {
  console.log("Property name is " + prop);
  console.log("Property value is " + object[prop]);
}  
           

但是for-in循环有一个问题,就是它不仅遍历对象的实例属性,同样还遍历从原型继承来的属性。当遍历自定义对象的属性石,往往会因为意外的结果而终止,处于这个原因,最好使用hasWwnProperty()来为 for-in 循环过滤出实例属性,比如

var prop;
for (prop in object) {
  if(object.hasOwnProperty(prop)){
    console.log("Property name is " + prop);
    console.log("Property value is " + object[prop]);
  }
}
           

变量函数和运算符

  变量声明:javascript中存在变量声明提前的概念:在函数内部任意地方定义变量何在函数顶部定义变量是完全一样的,因此,一种好的风格是将所有变量声明放在函数顶部而不是散落在各个角落。同时,使用单var进行变量声明,比如

function doSomethingWithItems(items) {

  var i, len,
      value = 10,
      result = value + 10;

  for (i=0, len=items.length; i < len; i++) {
    doSomething(items[i]);
  }    
}
           

  和变量声明一样,函数声明也会被JavaScript引擎提前。因此,代码中函数的调用可以出现在函数声明之前。但是一种好的风格是,先声明函数然后使用函数,而且函数内部的局部函数应当紧接着变量声明之后声明。

  相等:JavaScipt 具有强制类型转换机制,且这个机制是很微妙的,对于某些运算来说,为了取得成功的结果,强制类型转换会驱使某种类型的变量自动转换成其他不同类型,从而往往造成意想不到的结果。发生强制类型转换最常见的场景就是,使用了判断相等运算符 == 和!=的时候。当要比较两个值得类型不同是,这两个运算符都会有强制类型转换。但是很多实际情况中,代码并不按照我们所期望的方式运行。

  PS:相等操作符会对操作值进行隐式转换后进行比较:

  1)如果一个操作值为布尔值,则在比较之前先将其转换为数值

  2)如果一个操作值为字符串,另一个操作值为数值,则通过Number()函数将字符串转换为数值

  3)如果一个操作值是对象,另一个不是,则调用对象的valueOf()方法,得到的结果按照前面的规则进行比较

  4)null与undefined是相等的

  5)如果一个操作值为NaN,则相等比较返回false

  6)如果两个操作值都是对象,则比较它们是不是指向同一个对象

  所以,我推荐所有的判断相等都采用 === 和 !== ,不仅判断类型同时也判断数值上的相等,避免了强制类型转换带来的模棱两可的结果判定

  未完待续~

继续阅读