《JavaScript 闯关记》之语句

表达式在 JavaScript 中是短语,那末语句就是整句敕令。表达式用来盘算出一个值,语句用来实行以使某件事发作。从本质上看,语句定义了 JavaScript 中的重要语法,语句平常运用一或多个症结字来完成给定使命。语句可以很简单,比方关照函数退出;也可以比较庞杂,比方指定反复实行某个敕令的次数。下表列出了 JavaScript 大部份语句的语法和用处:

语句语法用处
breakbreak [label];退出最内层轮回或许退出 switch 语句,又或许退出 label 指定的语句
casecase expression:switch 语句中标记一条语句
continuecontinue [label];从新最先最内层的轮回或从新最先 label 指定的轮回
debuggerdebugger;断点器调试
defaultdefault;switch 中标记默许的语句
do-whiledo statement while(expression); while 轮回的一种替换情势
empty;什么都不做
forfor(init;expr;incr) statement简写的轮回组织
for-infor(var in object) statement遍历一个对象的属性
function function name([param[],...])
{statement}
声明一个函数
if-else if (expression) statement1
[else statement2]
实行 statement1 或许 statement2
labellabel:statementstatement 指定一个名字 label
returnreturn [expression];从函数返回一个值
switchswitch(expression){statement}case 或许 default 语句标记的多分支语句
throwthrow expression;抛出异常
try try {statement}
[catch {handler statement}]
[finally {cleaup statement}]
捕捉异常
use strict"use strict"对剧本和函数运用严厉形式
varvar name=[=expr][,...];声明并初始化一个或多个变量
whilewhile(expression) statement基础的轮回组织
withwith(object) statement扩大作用域链

前提语句

if-else 语句

大多数编程言语中最为常常使用的一个语句就是 if-else 语句。以下是 if-else 语句的语法:

if (condition) statement1 [else statement2]

个中的 condition 可以是恣意表达式;而且对这个表达式求值的效果不肯定是布尔值。JavaScript 会自动挪用 Boolean() 转换函数将这个表达式的效果转换为一个布尔值。如果对 condition 求值的效果是 true,则实行 statement1,如果对 condition 求值的效果是 false,则实行 statement2。而且这两个语句既可以是一行代码,也可以是一个代码块(以一对花括号括起来的多行代码)。请看下面的例子:

if (i > 25)
    console.log("Greater than 25.");              // 单行语句
else {
    console.log("Less than or equal to 25.");     // 代码块中的语句
}

业界广泛推重的最好实践是一向运用代码块,纵然要实行的只要一行代码。因为如许可以消弭人们的误会,不然可以让人分不清在差别前提下要实行哪些语句。

switch 语句

switch 语句与 if 语句的关联最为亲昵,而且也是在其他言语中广泛运用的一种流掌握语句。JavaScript 中 switch 语句的语法与其他基于 C 的言语异常靠近,以下所示:

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

switch 语句中的每一种状况的寄义是:“如果表达式即是这个值(value),则实行背面的语句(statement)”。而 break 症结字会致使代码实行流跳出 switch 语句。如果省略 break 症结字,就会致使实行完当前 case 后,继承实行下一个 case。末了的 default 症结字则用于在表达式不婚配前面任何一种状况的时刻,也相当于一个 else 语句。从根本上讲,switch 语句就是为了让开辟人员免于编写像下面如许的代码:

if (i === 25){
  console.log("25");
} else if (i === 35) {
  console.log("35");
} else if (i === 45) {
  console.log("45");
} else {
  console.log("Other");
}

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

switch (i) {
    case 25: 
        console.log("25");
        break;
    case 35: 
        console.log("35");
        break;
    case 45: 
        console.log("45");
        break;
    default: 
        console.log("Other");
}

经由过程为每一个case背面都增加一个break语句,就可以防止同时实行多个case代码的状况。如果确切须要夹杂几种状况,不要忘了在代码中增加诠释,申明你是故意省略了break症结字。

虽然 JavaScript 中的 switch 语句自创自其他言语,但这个语句也有本身的特征。起首,可以在 switch 语句中运用任何数据范例(在许多其他言语中只能运用数值),无论是字符串,照样对象都没有题目。其次,每一个 case 的值不肯定是常量,可以是变量,以至是表达式。请看下面这两个例子:

switch ("hello world") {
    case "hello" + " world": 
        console.log("Greeting was found.");
        break;
    case "goodbye": 
        console.log("Closing was found.");
        break;
    default: 
        console.log("Unexpected message was found.");
}

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

switch 语句起首盘算 switch 症结字后的表达式,然后根据从上到下的递次盘算每一个 case 后的表达式,直到实行到 case 的表达式的值与 switch 的表达式的值相称时为止。因为对每一个 case 的婚配操纵实际上是 === 恒等运算符比较,而不是 == 相称运算符比较,因而,表达式和 case 的婚配并不会做任何范例转换。

轮回

while 语句

while 语句属于前测试轮回语句,也就是说,在轮回体内的代码被实行之前,就会对出口前提求值。因引,轮回体内的代码有可以永久不会被实行。以下是 while 语句的语法:

while(expression) statement

下面是一个示例:

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

do-while 语句

do-while 语句是一种后测试轮回语句,即只要在轮回体中的代码实行以后,才会测试出口前提。换句话说,在对前提表达式求值之前,轮回体内的代码最少会被实行一次。以下是 do-while 语句的语法:

do {
    statement
} while (expression);

下面是一个示例:

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

for 语句

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

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

下面是一个示例:

var count = 10;
for (var i = 0; i < count; i++){
    console.log(i);
}

这个 for 轮回语句与下面的 while 语句的功用雷同:

var count = 10;
var i = 0;
while (i < count){
    console.log(i);
    i++;
}

因为 JavaScript 中不存在块级作用域,因而在轮回内部定义的变量也可以在外部访问到。比方:

var count = 10;
for (var i = 0; i < count; i++){
    console.log(i);
}
console.log(i); // 10

另外,for 语句中的初始化表达式、掌握表达式和轮回后表达式都是可选的。将这两个表达式悉数省略,就会建立一个无穷轮回,比方:

// 无穷轮回
for (;;) {
    doSomething();
}

for-in 语句

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

for (property in object) statement

下面是一个示例:

for (var propName in window) {
    console.log(propName);
}

在这个例子中,我们运用 for-in 轮回来显现了 BOM 中 window 对象的一切属性。每次实行轮回时,都会将 window 对象中存在的一个属性名赋值给变量 propName。这个历程会一向延续到对象中的一切属性都被罗列一遍为止。与 for 语句相似,这里掌握语句中的 var 操纵符也不是必须的。然则,为了保证运用部份变量,我们引荐上面例子中的这类做法。

JavaScript 对象的属性没有递次。因而,经由过程 for-in 轮回输出的属性名的递次是不可展望的。细致来说,一切属性都会被返回一次,但返回的前后序次可以会因浏览器而异。

如果示意要迭代的对象的变量值为 nullundefinedfor-in 语句会抛出毛病。虽然 ECMAScript 5改正了这一行动;对这类状况不再抛出毛病,而只是不实行轮回体。为了保证最大限制的兼容性,发起在运用 for-in 轮回之前,先检测确认该对象的值不是 nullundefined

跳转

label 语句

运用 label 语句可以在代码中增加标签,以便未来运用。以下是 label 语句的语法:

label: statement

下面是一个示例:

start: for (var i=0; i < count; i++) {
    console.log(i); 
}

这个例子中定义的 start 标签可以在未因由 breakcontinue 语句援用。加标签的语句平常都要与 for 语句等轮回语句合营运用。

breakcontinue 语句

breakcontinue 语句用于在轮回中精确地掌握代码的实行。个中,break 语句会马上退出轮回,强迫继承实行轮回背面的语句。而 continue 语句虽然也是马上退出轮回,但退出轮回后会从轮回的顶部继承实行。请看下面的例子:

var num = 0;

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

console.log(num);   // 4

这个例子中的 for 轮回会将变量 i 由1递增至 10。在轮回体内,有一个 if 语句搜检 i 的值是不是可以被 5 整除(运用求模运算符)。如果是,则实行 break 语句退出轮回。另一方面,变量 num0 最先,用于纪录轮回实行的次数。在实行 break 语句以后,效果显现 4。也就是说,在变量 i 即是 5 时,轮回统共实行了 4 次;而 break 语句的实行,致使了轮回在 num 再次递增之前就退出了。如果在这里把 break 替换为 continue 的话,则可以看到另一种效果:

var num = 0;

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

console.log(num);   // 8

例子的效果显现 8,也就是轮回统共实行了 8 次。当变量 i 即是 5 时,轮回会在 num 再次递增之前退出,但接下来实行的是下一次轮回,即i的值即是 6 的轮回。因而,轮回又继承实行,直到 i 即是 10 时天然完毕。而 num 的终究值之所所以 8,是因为 continue 语句致使它少递增了一次。

breakcontinue 语句都可以与 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++;
    }
}

console.log(num);   // 55

在这个例子中,outermost 标签示意外部的 for 语句。如果每一个轮回一般实行 10 次,则 num++ 语句就会一般实行 100 次。换句话说,如果两个轮回都天然完毕,num 的值应该是 100。但内部轮回中的 break 语句带了一个参数:要返回到的标签。增加这个标签的效果将致使 break 语句不仅会退出内部的 for 语句(即运用变量 j 的轮回),而且也会退出外部的 for 语句(即运用变量 i 的轮回)。为此,当变量 ij 都即是 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++;
    }
}

console.log(num);   // 95

在这类状况下,continue 语句会强迫继承实行轮回,退出内部轮回,实行外部轮回。当 j5 时,continue 语句实行,而这也就意味着内部轮回少实行了 5 次,因而 num 的效果是 95

虽然联用 breakcontinuelabel 语句可以实行庞杂的操纵,但如果运用过分,也会给调试带来贫苦。在此,我们发起如果运用 label 语句,肯定要运用描述性的标签,同时不要嵌套过量的轮回。

return 语句

return 语句的作用是指定函数挪用后的返回值。return 语句的语法以下:

return [expression];

下面是一个示例:

function square(x) { return x*x; }  // 一个包括 return 语句的函数
square(2);                          // 挪用效果为 4

return 语句只能在函数体内涌现,如果不是的话会报语法毛病。当实行到 return 语句的时刻,函数住手实行,并返回 expression 的值给挪用顺序。如果没有 return 语句,则函数挪用仅顺次实行函数体内的每一条语句直到函数完毕,末了返回挪用顺序。这类状况下,挪用表达式的效果是 undefinedreturn 语句常常作为函数内的末了一条语句涌现,但并不是说要肯定放在函数末了。return 语句可以零丁运用而没必要带有 expression,如许的话函数也会向挪用顺序返回 undefined

因为 JavaScript 可以自动插进去分号,因而在 return 症结字和它背面的表达式之间不能有换行。

throw 语句

throw 语句的作用是把顺序运转时发生的毛病显式地抛出异常。throw 语句的语法以下:

throw expression;

expression 的值可以是恣意范例的。可以抛出一个代表毛病码的数字,或许包括可读的毛病音讯的字符串。当 JavaScript 诠释器抛出异常的时刻平常采纳 Error 范例和其子范例。Error 对象有一个 name 属性示意毛病范例,一个 message 属性用来寄存传递给组织函数的字符串,鄙人面的例子中,当运用不法参数挪用函数时就抛出一个 Error 对象:

function factorial(x) {
// 如果输入参数是不法的,则抛出一个异常
    if (x < 0) throw new Error("x不能是负数");
    // 不然,盘算出一个值,并一般地返回它
    for(var f = 1; x > 1; f *= x, x--) /* empty */ ;
    return f;
}

当抛出异常时,JavaScript 诠释器会马上住手当前正在实行的逻辑,并跳转至就近的异常处置惩罚顺序。如果没有找到任何异常处置惩罚顺序,异常就会沿着 JavaScript 要领的词法组织和挪用栈向上流传。终究 JavaScript 将把异常当做顺序毛病来处置惩罚,并报告给用户。

try 语句

try-catch-finally 语句是 JavaScript 中异常处置惩罚机制,try-catch-finally 语句的语法以下:

try {statement} [catch {handler statement}] [finally {cleaup statement}]

try 从句定义了须要处置惩罚的异常地点的代码块。catch 从句追随在 try 从句以后,当 try 块内某处发作了异常时,挪用 catch 内的代码逻辑。catch 从句后追随 finally 块,后者中安排清算代码,不论 try 块中是不是发生异常,finally 块内的逻辑总是会实行。只管 catchfinally 都是可选的,但 try 从句须要最少两者之一与之构成完全的语句。trycatchfinally 语句块都须要运用花括号括起来,这里的花括号是必须的,纵然从句中只要一条语句也不能省略花括号。

下面的代码细致的申清楚明了 try-catch-finally 的运用目标:

try {
    // 平常来说,这里的代码会从新实行到尾而不会发生任何题目,
    // 但有时会抛出一个异常,要么是由 throw 语句直接抛出异常,
    // 要么是经由过程挪用一个要领间接抛出异常
}
catch(e) {
    // 当且仅当 try 语句块抛出了异常,才会实行这里的代码
    // 这里可以经由过程部份变量 e 来取得对 Error 对象或许抛出的其他值的援用
    // 这里的代码块可以基于某种原因处置惩罚这个异常,也可以疏忽这个异常,
    // 还可以经由过程 throw 语句从新抛出异常
}
finally {
    // 不论 try 语句块是不是抛出了异常,这里的逻辑总是会实行,住手 try 语句块的体式格局有:
    // 1)一般住手,实行完语句块的末了一条语句
    // 2)经由过程 break、continue 或 return 语句住手
    // 3)抛出一个异常,异常被 catch 从句捕捉
    // 4)抛出一个异常,异常未被捕捉,继承向上流传
}

其他

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 语句。严厉形式下不许可运用 with 语句,不然将视为语法毛病。

debugger 语句

debugger 语句平常什么也不做。但是,当浏览器的调试东西可用并运转的时刻,JavaScript 诠释器将会以调式形式运转。实际上,这条语句用来发生一个断点(breakpoint),JavaScript 代码的实行会住手在断点的位置,这时候可以运用调试器输出变量的值、搜检挪用栈等。比方:

function f(o) {
    if (o === undefined) {
        debugger;  // 顺序会住手在该位置
    }
    // 函数的其他部份
}

use strict 语句

请拜见「语法」-「严厉形式」

关卡

// 应战一
var k;
for(i=0, j=0; i<10, j<6; i++, j++){
    k = i + j;
}
console.log(k);  // ???
// 应战二
var nums = [12,32,54,56,78,89];
for(var n in nums){
    console.log(n);  // ???
}
// 应战三
function showCase(value) {
    switch (value) {
        case 'A':
            console.log('Case A');
            break;
        case 'B':
            console.log('Case B');
            break;
        case undefined:
            console.log('undefined');
            break;
        default:
            console.log('Do not know!');
    }
}
showCase(new String('A'));   // ???
// 应战四
function showCase(value) {
    switch (value) {
        case 'A':
            console.log('Case A');
        case 'B':
            console.log('Case B');
            break;
        case undefined:
            console.log('undefined');
            break;
        default:
            console.log('Do not know!');
    }
}
showCase(String('A'));   // ???
// 应战五
var i = 0;
for (;;) {
    if (i = 2) {
        continue;
    }
    if (i = 20) {
        break;
    }
    i++;
}
console.log(i);  // ???

更多

关注微信民众号「劼哥舍」复兴「答案」,猎取关卡详解。
关注 https://github.com/stone0090/javascript-lessons,猎取最新动态。

    原文作者:劼哥stone
    原文地址: https://segmentfault.com/a/1190000006769967
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞