JavaScript提升系列(六):语句

本文总结

  • ECMAScript中不存在块级作用域,因此循环内部定义的变量也可以在外部访问到。(ES6中新增let关键字,可以定义块级作用域的变量)
  • ECMAScript中的对象没有顺序,因此通过for-in语句遍历对象属性的顺序是不可预测的。
  • 如果迭代的对象值为nullundefined,ES5以上不执行循环体。(ES5以下会抛出错误)
  • 大量的with语句会造成性能问题,在大型应用中,不建议使用with语句。

与C++/Java不同之处

  • 用于循环嵌套场景的break <label>continue <label>语句。(C/C++虽然有这个语句,但一般与goto搭配使用,不能和breakcontinue使用)
  • with语句,限定语句作用域于某个对象。(C++没有此语句)
  • switch语句可以用于任意类型,每个case的值可以是常量,变量,字符串,对象,甚至是表达式。(C++中,只能为整型家族的值)

严格模式

  • 严格模式下,不允许使用with语句,将会被视为语法错误。

——————————————正文分割线——————————————————

if 语句

大多数编程语言中最常用的一个语句就是if语句,以下是if语句的用法:

if( condition ){
  statement1
}
else {
  statement2
}

其中condition可以是任意表达式,而且表达式求值的结果不一定是布尔值,ECMAScript会自动调用Boolean()转换函数将这个表达式的结果转换为布尔值。

do-while语句

do-while语句是一种后测试循环语句,只有在循环体中的代码执行之后,才会测试出口条件,以下是其用法:

var i = 0;
do {
  i += 2;
} while( i<10 );
alert(i);

while语句

while语句属于前测试循环语句,也就是说,在循环体代码被执行之前,就会对出口条件求值,以下是其用法:

var i = 0;
while( i<10 ){
  i+=2;
}
alert(i);

for语句

for语句也是前测试循环语句,但它具有在执行循环之前初始化变量和定义循环后要执行的代码的能力,以下是其用法:

var count = 10;
for ( var i=0; i<count; ++i ) {
  alert(i);
}

for循环语句与下面的while语句功能相同:

var count = 0;
var i = 0;
while ( i<count ){
  alert(i);
  ++i;
}

使用while循环做不了的,使用for循环同样也做不到。
for循环的变量初始化表达式中,也可以不使用var关键字,该变量的初始化可以在外部执行,例如:

var count = 10;
var i;
for ( i=0; i<count; ++i ){
  alert(i);
}

以上代码在循环初始化表达式中声明变量的效果是一样的。
由于ECMAScript中不存在块级作用域,因此循环内部定义的变量也可以在外部访问到,例如:

var count = 10;
for ( var i=0; i<count; ++i ){
  alert(i);
}
alert(i);    //  i = 10

在这个例子里,会有一个警告框显示循环完成后变量i的值,这个值是10。
这是因为,即使i是在循环内部定义的一个变量,但在循环外部仍然可以访问它。
此外,for语句中的初始化表达式、控制表达式和循环后表达式都是可选的,将两个表达式全部省略,就会创建一个无限循环,例如:

for (; ; ;) {
  doSomething();
}

而只给出控制表达式实际上就把for循环转换成了while循环,例如:

var count = 10;
var i = 0;
for (; i<count; ) {
  alert(i);
  ++i;
}

由于for语句存在极大的灵活性,因此它也是ECMAScript中最常用的一个语句。

for-in语句

for-in语句是一种精准的迭代语句,可以用来枚举对象的属性,以下是for-in语句的用法:

for ( var propName in window ) {
  document.write(propName);
}

for语句类似,这里控制语句中的var操作符也不是必需的,但为了保证使用局部变量,我们推荐上面例子中的这种做法。
ECMAScript对象的属性没有顺序,因此通过for-in语句循环输出的属性名顺序是不可预测的

label语句

使用label语句可以在代码中添加标签,以便将来使用,以下是其用法:

start : for ( var i=0; i<10; ++i ) {
  alert(i);
}

这个例子中定义的start标签可以在将来由breakcontinue语句引用,加标签的语句一般都与for语句等循环语句配合使用。

break和continue语句

breakcontinue语句用于在循环中精确地控制代码的执行。
break,立刻退出循环。
continue,退出本次循环,进入下次循环。
使用break例子如下:

var num = 0;
for ( var i=1; i<10; i++ ) {
  if ( i%5==0 ){
    break;
  }
num++;
}
alert(num);    //4

使用continue例子如下:

var num = 0;
for ( var i=0; i<10; ++i ){
  if ( i%5==0 ) {
    continue;
  }
  num++;
}
alert(num);  //8

breakcontinue语句都可以与label语句联合使用,从而返回代码中特定的位置,这种联合使用多用于循环嵌套的情况下,如下例:

var num = 0;
outerLabel:
  for( var i=0; i<10; ++i ){
    for( var j=0; j<5; ++j ){
      if( j==2 ){
        break outerLabel;
      }
      num++;
    }
  }
alert(num);    //2

上述例子中,在内层循环时,判断j变量等于2的时候,进行break,此处的break指定了一个outerLabel,意味着,从outerLabel标记的循环中进行break,因此上述的嵌套循环只执行了2次。

with语句

with语句的主要作用是将代码的作用域设置到一个特定的对象中。
不使用with的情况:

var gs = location.search.substring(1);
var hostName = location.hostname;
var url = location.href; 

使用with语句简化代码:

with(location){
  var gs = search.substring(1);
  var hostName = hostname;
  var url = href;
}

上述例子中,每个变量首先被认为是局部变量,如果局部变量中找不到该变量的定义,就会查询location对象中是否有同名的属性。
严格模式下不允许使用with语句,否则将视为语法错误。
大量使用with语句会导致性能下降,同时也会被代码调试造成困难,因此在开发大型应用程序时,不建议使用with语句。

Switch 语句

switch语句与if语句的关系最为密切,而且也是其他语言中普遍使用的一种流控制语句,例子如下:

switch (i) {
  case 25:
    alert("25");
    break;
  case 35:
    alert("35");
    break;
  default:
    alert("other");
}

ECMAScript中的switch语句可以用于任何数据类型,无论是字符串还是对象都没有问题,其次每个case值不一定是常量,可以是变量,甚至是表达式。

switch ("Hello World") {
  case "Hello "+ "World":
    alert("Greeting was found!");
    break;
  case "goodBye":
    alert("Closing was found!");
    break;
  default:
    alert("Unexpected message was found!");
}

除上述例子外,使用表达式作为case值还可以实现下列操作:

var num = 25;
switch (true) {
  case num < 0:
    alert("Less than 0");
    break;
  case num>=0 && num <=10:
    alert("Between 0 and 10.");
    break;
  case num>10 && num<=20:
    alert("Between 10 and 20.");
    break;
  default:
    alert("More than 20.");
}

之所以给switch语句传递表达式true是因为每个case值都可以返回一个布尔值。
switch语句在比较值时,使用的是全等操作符,因此不会发生类型转换。

完!