首页 » JavaScript » 语句

语句

If 语句

if 语句是基本的控制语句,它使得JavaScript进行选择,更准确的说,就是有条件地执行语句。这个语句有两种形式,第一种形式是:

if (expression)
    statement

在这种形式中,expression是要被计算的,如果计算的结果是true,或者可以被转换成true,那么就执行statement。如果expression的值为false,或者可以被转换成false,那么就不执行statement。例如:

if (username == null)
    username = "John Doe"

同样:

if (!username) username = "John Doe"

虽然在这里看起来扩起表达式的括号无关紧要,但是它们确实If语句的语法所必须的一部分。
我们在前面提到过,可以使用一个语句块来替换单个的语句,所以if语句也可以用如下代码:

if((address ==null)||(address == "")){
    address = "undefined";
    alert("Please specify a mailing address.");
}

在这些例子中,格式上的缩进不不是必须的。JavaScript会把多余的空格都忽略掉。而且,由于我们在每条语句之后都用了分号,所以可以将例子中的所有代码都写到一行中。但是想上例所示的那样使用换行和缩进会使得代码更易读,也更容易理解。

if语句的地中形式引入了else从句,当expression的值是false是,就执行这个从句。它的语法如下:

if (expression)
    statement1
else
    statement2

在这种形式中,先计算expression的值,如果踏实true,就执行stement1,否则就执行statement2。例如:

if (username != null)
    alert("hello" + username +"\n What is your name?");
else {
    alert("hello" + username);
}

当在具有else从句的if语句中进行嵌套时,注意确保else语句匹配了正确的if语句。考虑如下的代码:

i = j = 1;
k = 2;
if (i == j)
    if (j == k)
        document.write("i equals k");
else
    document.write("i doesn't equal j");

在这个例子中,内层的if语句构成了外层的if语句所需要的子语句。但是,if和else是如何匹配的并不十分清除。而且,在这个例子中,缩进的给出暗示也是错误的,因为JavaScript的解释器实际上将上面的这个例子解释为:

if (i ==j){
    if (j ==k)
        document.write("i equals k");
    else
    document.write(”i doesn't equal j");
}

JavaScript中的规则(和大多数程序设计语言一样)是,else从句是离它最近的if语句的一部分。要使用这个例子更易读、易理解、易支持和调试,可以使用花括号:

if (i == j) {
    if (j == k) {
        documnet.write("i equals k");
    }
} else {
    document.write("i doesn't equal j");
}

do-while

do-while语句是一种后测试循环语句,即只有在循环体中的代码执行之后,才会测试出口条件。换句话说,在对条件表达式求值之前,循环体内的代码至少执行一次。以下是do-while语句的语法:

do {
    statement
} while (expression);

下面是一个实例:

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

在这个例子中,只要变量i的值小于10,循环就会就会一直继续下去。而且变量i的值最初为0,每次递增都会递增2。

while

while语句术语前测试循环语句,也就是说,在循环体内的代码被执行之前,就会对出口条件求值。因此,循环体内的代码有可能永远不会被执行。以下是while语句的语法:

while (expression) statement

下面是一个实例:

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

在这个例子中,变量i开始时的值为0,每次循环都会递增2.而只要i的值小于10,循环就会继续下去。

for

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

for (intialization; expression; post-loop-expression) statement

下面是一个实例:

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

以上代码定义了变量i的初始值为0。只有当表达式(i<count)返回true的情况下才会进入for循环,因此也有可能不会执行循环体中的代码。如果执行了循环体中的代码,则一定会对循环后的表达式(i++)求值,即递增i的值。这个for 循环语句与下面的while语句的功能相同:

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

使用while循环做不到的,使用for循环同样也做不到。也就是说,for循环只是把与循环有关的代码集中在了一个位置。

有必要指出的是,在for循环的变量初始化表达式中,也可以不实用var关键字。改变量的初始化可以在外部执行,例如:

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

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

var count = 10;
var i;
for (i = 0; i < count; i++) {
    alert(i);
}
alert(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 (property in expression) statement

下面是一个示例:

for (var propName in window) {
    document.write(propName);
    document.write("<br/>")
}

在这个例子中,我们使用for-in循环来显示了BOM中window对象的所有属性。每次执行循环时,都会将window对象中存在的一个属性名赋值给变量propName。这个过程会一直持续到对象中的所有属性都被枚举一遍为止。与for语句类似,这里控制语句中的var运算符也不是必须的。但是为了保证使用局部变量,我们推荐上面例子中的这种做法。

ECMAScript对象的属性没有顺序。因此,通过for-in循环输出的属性名的顺序是不可预测的。具体来讲,所有属性都会被返回一次,但返回的先后次序可能会因为浏览器而异。

但是,如果表示要迭代的对象的变量值为null或undefined,for-in语句会抛出错误。ECMAScript5 更正了这一行为;对这种情况不再抛出错误,而只是不执行循环体。为了保证最大限度的兼容性,建议在使用for-in循环之前,先检测确认该对象的值不是null或undefined。

Safari 3以前版本的for-in语句中存在一个bug,该bug会导致某些属性被返回两次。

label

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

label: statement

下面是一个示例:

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

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

break 和 continue

break和continue语句用于在循环中精确地控制代码的执行。其中,break语句会立即退出循环,强制继续执行循环后面的语句。而continue语句虽然也是立即退出循环,但退出循环后会从循环的顶部继续执行。请看下面的代码:

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

这个例子中的for循环将变量i由1递增至10.在循环体内,有一个if语句检查i的值是否可以被5整除(使用求模操作符)。如果是,则执行break语句退出循环。另一方面,变量num从0开始,用于记录循环执行的次数。在执行brak语句之后,要执行的下一行代码是alert()函数,结果显示4。也就是说,在变量i等于5时,循环总共执行了4次;而brak语句的执行,导致了循环在num再次递增之前就退出了。如果在这里把break替换为continue的话,则可以看到另一种结果:

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

例子的结果显示8,也就是循环总共执行了8次。当变量i=5时,循环会在num再次递增之前退出,但接下来执行的是下一次循环,即i的值等于6的循环。于是,循环有继续执行,直到i等于10时自然结束。而num的最终值之所以是8,是因为continue语句导致它少递增了一次。

break和continue语句都可以与label语句联合使用,从而返回代码中特定的位置。这种联合使用的情况多发生在循环套的情况下,如下面的例子所示:

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

在这个例子中,outermost标签表示外部的for语句。如果每个循环正常执行10次,则num++语句就会正常执行100次。换句话说,如果两个循环都自然结束,num的值应该是100.但内部循环中的break语句带了一个参数:要返回的标签。添加这个标签的结果就导致break语句不仅会退出内部的for语句(即使变量j的循环),而且也会退出外部的for语句(即使用变量i的循环)。为此,当变量i和j都等于5时,num的值正好是55.同样,continue语句也可以想这样与label语句联用,如下面的例子所示:

var num = 0;
outermost: for (var i = 0; i < 10; i++) {
    for (var j = 0; j < 10; j++) {
        if (i == 5 && j == 5) {
            continue outermost;
        }
        num++;
    }
}
alert(num);    //95

在这种情况下,continue语句会强制继续执行循环——退出内部循环,执行外部循环,当j是5时,continue语句执行,而这也就是意味着内部循环少执行了5次,因此num的结果是95。
虽然联用break、continue和label语句能够执行复杂的操作,但如果使用过度,也就会给调试带来麻烦。再次,我们建议如果使用label语句,一定要使用描述性的标签,同时不要嵌套过多的循环。

with

with语句的作用是将代码的作用域设置到一个特定的对象中。with语句的语法如下:

with (expression) statement

定义with语句的目的主要是为了简化多次编写同一个对象的工作,如下面的例子所示:

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

上面的几行代码都包含location对象。如果使用with语句,可以把上面的代码改写成如下所示:

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

在这个重写例子中,使用with语句关联了location对象。这意味着在with语句的代码块内部,每个变量首先被认为是一个局部变量,而如果在局部环境中找不到该变量的定义,就会查询location对象中是否有同名的属性。如果发现了同名属性,则以location对象属性的值作为变量的值。

由于大量使用with语句会导致性能下降,同时也会给调试代码造成困难,因此在开发大型应用程序时,不建议使用with语句。

switch

switch语句与if语句的关系最为密切,而且也是在其它语言中普遍使用的一种流程控制语句。ECMAScript中switch语句的语法与其他基于C的语言非常接近,如下所示:

switch (expression) {
case value:
    statement
    break;
case value:
    statement
    break;
case value:
    statement
    break;
case value:
    statement
    break;
default:
    statement
}

switch语句中的每一种情形(case)的含义是”如果表达式等于这个值(value),则执行后面的语句(statement)“.而break关键字会导致代码执行流跳出switch语句。如果省略了break关键字,就会导致执行完当前case后,继续执行下一个case。最后的default关键字则用于在表达式不匹配前面任何一种情形的时候,执行机动代码(因此,也相当于一个else语句)。

从根本上讲,switch语句就是为了让开发人员免于编写像下面这样的代码:

var i = 25;
if (i == 25) {
    alert("25")
} else if (i == 35) {
    alert("35")
} else if (i == 45) {
    alert("45")
} else {
    alert("Other");
}

而与此等价的switch语句如下所示:

var i = 25;
switch (i) {
case 25:
    alert("25");
    break;
case 35:
    alert("35");
    break;
case 45:
    alert("45")
    break;
default:
    alert("Other");
}

通过为每个case后面都添加一个break语句,就可以避免同时执行多个case代码的情况。假如确实需要混合几种情形,不要忘了在代码中添加注释,说明你是有意省略了break关键字,如下所示:

var i = 25
switch (i) {
case 25:    //合并两种情形
case 35:
    alert("25 or 35");
    break;
case 45:
    alert("45");
    break;
default:
    alert("Other");
}

虽然ECMAScript中的switch语句借鉴自其它语言,但这个语句也有自己的特色。首先,可以在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.");
}

在这个例子中,switch语句使用的就是字符串。其中,第一种情形实际上是一个对字符串拼接操作求值的表达式。由于这个字符串拼接表达式的结果与switch的参数相等,因此结果就会显示“Greeting 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.");
default:
    alert("More than 20.");
}

这个例子首先在switch语句外声明了变量num。而之所以给switch语句传递表达式true,是因为每个case值都可以返回一个布尔值。这样,每个case 按照顺序被求值,直到找到匹配的值或者遇到default语句为止(这正式这个例子的最终结果)。

此文章发表在 JavaScript. 将 固定链接 加入收藏.