一、概述
从程序流程的角度来看,程序可以分为三种基本结构:顺序结构、分支结构(又称选择结构)、循环结构。这三种基本结构可以组成所有的各种复杂程序。JavaScript提供了多种语句来实现这些程序结构。
二、顺序结构
顺序结构即程序从上往下依次执行语句。
三、分支结构 *
分支结构主要包括条件语句( if 语句)与分支语句( switch 语句)。
3.1、条件语句
3.1.1、if 语句
if 语句会对一个条件进行判断,如果这个条件的结果为 true,就会执行后续代码块中的语句。其语法形式为:
if (condition) {
// code...
};
var age = 26;
if(age >= 18) {
console.log("成年");
}
我们再来看一个复杂一点的关于求闰年的练习:
var year = 2019;
if((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
console.log(year + '是闰年');
}
提示:闰年是能被4整除但不能被100整除,或者能被400整除的年份,因此,我们可以得出判断条件:
year % 4 == 0 && year % 100 != 0
year % 400 == 0
只要这个条件为真,则是闰年,否则为平年。
3.1.2、if-else 语句
if-else 语句通常用来进行条件判断,如果条件的结果是 true,那么第一个代码块会被执行,如果条件的结果是 false,那么第二个代码块会被执行,其语法形式如下:
if(condition) {
// 代码块1
}else {
// 代码块2
}
我们来看一个例子,判断用户是否登录成功,如果用户登录成功,则弹框提示‘恭喜您,登录成功!’,否则弹框提示‘对不起,登录失败!’。
<!-- index.htlm -->
<form name="myForm" action="javascript:;" method="POST" target="_blank" accept-charset="UTF-8">
<label>账号:</label><input type="text" id="account" placeholder="请输入账号">
<br>
<label>密码:</label><input type="password" id="password" placeholder="请输入密码">
<br><br>
<button type="button" id="loginBtn">登录</button>
</form>
// index.js
// 获取元素
let accountIpt = document.getElementById('account');
let passwordIpt = document.getElementById('password');
let loginBtn = document.getElementById('loginBtn');
// 为loginBtn添加点击事件
loginBtn.onclick = function() {
// 获取账号密码值
var accountText = accountIpt.value;
var passwordText = passwordIpt.value;
// 判断用户是否登录成功,正确账号:Admin 密码:123
if ((accountText == "Admin") && (passwordText == "123")) {
alert('恭喜您,登录成功!');
} else {
alert('对不起,登录失败!');
}
}
上述登录按钮点击事件触发函数中,通过 if 语句判断,在判断条件中,由于登录成功需要账号密码同时正确才满足条件,因此我使用了 && 逻辑运算符,程序首先会去判断 && 运算符前后的两个表达式的值,如果两个表达式的值同时为true,则会执行第一个代码块,否则会执行第二个代码块的内容。
tips:一般情况下,else 匹配的是排除if条件之外的所有情况。对于 if-else 语句,我们可以转换为三目运算符(a ? b : c) 来表示。
3.1.3、if-else if-else 语句
if 语句还有更复杂的使用方法,即 if-else if-else 语句,前两种形式的if语句一般都用于两个分支的情况。当有多个分支选择时,可采用 if-else if-else 语句。我们来看一个示例:
var score = 92;
if(score >= 90 && score <= 100) {
console.log('优秀!');
}else if(score >= 70 && score < 90) {
console.log('良好!');
}else if(score >= 60 && score < 70) {
console.log('及格!');
}else if(score >= 0 && score < 60) {
console.log('不及格!');
}else {
console.log('成绩有误!');
}
// 注意:else 如果后面没有跟上if,则表示排除以上所有情况之外的情况,在这里当成绩小于0或成绩大于100时执行;
if-else if-else 语句,依次判断表达式的值,当出现某个值为真时,则执行其对应的语句,然后跳到整个if语句之外继续执行程序。如果所有的表达式均为假,则执行 else 后的代码块,然后继续执行后续程序。
tips:在使用 if 语句中还应注意以下问题:
- 在三种形式的if语句中,
if关键字之后均为表达式,该表达式通常是逻辑表达式或关系表达式,但也可以是其他表达式,如赋值表达式等,甚至也可以是一个变量。- 在
if语句中,条件判断表达式必须用括号括起来,在语句之后必须加分号。- 嵌套使用
if语句应该注意,else总是与它前面最近的if配对。
3.2、switch语句
switch 语句的开头是一个被称作分支值的变量,每个case表示一个条件,当条件的值和这个变量的值匹配时,它后面的代码就会被执行,下面是switch语句的语法:
switch (表达式) {
case 常量表达式1: 语句1;break;
case 常量表达式2: 语句2;break;
case 常量表达式3: 语句3;break;
...
case 常量表达式n: 语句n;break;
default: 语句n+1;
}
上述表达式的语义是:计算表达式的值,并逐个与其后的常量表达式值比较。当表达式的值与某个常量表达式的值相等时,即执行其后的语句,然后不再进行判断,继续执行后面所有case后的语句。如表达式的值与所有case的常量表达式均不相同时,则执行
default后的语句。语句后的break用于跳出switch,执行switch后面的内容。
var week = 2;
switch (week) {
case 1: { console.log('星期一'); } break;
case 2: { console.log('星期二'); } break; // 输出星期二
case 3: { console.log('星期三'); } break;
case 4: { console.log('星期四'); } break;
case 5: { console.log('星期五'); } break;
case 6: { console.log('星期六'); } break;
case 7: { console.log('星期天'); } break;
default: { console.log("异常!") }
}
上述示例中,判断 week 的值,与每一个case值匹配,匹配到值之后执行相应的代码块,然后执行 break 跳出switch语句,因此上述示例输出 “星期二 ”。如果没有添加 break 关键字,程序会执行从匹配到的case分支语句表达式及其之后的所有case分支语句表达式。
var cooking = '川菜';
switch (cooking) {
case '川菜': {
console.log('麻婆豆腐,回锅肉,宫保鸡丁。');
} break;
case '粤菜': {
console.log('梅菜扣肉,清蒸鲈鱼。');
} break;
case '湘菜': {
console.log('剁椒鱼头,霸王别姬。');
} break;
case '鲁菜': {
console.log('葱爆羊肉, 红烧海螺,锅塌豆腐。');
}break;
default: {
console.log('本店没有该菜系!');
}
}
// "麻婆豆腐,回锅肉,宫保鸡丁。"
switch 语句匹配区间:
var score = 60;
switch(true) {
case score >= 80 && score <= 100: {
console.log("优秀");
} break;
case score >= 60 && score < 80: {
console.log("良好");
} break;
case score >= 0 && score < 60: {
console.log("不及格");
}break;
default:{
console.log("成绩有误!");
}
}
tips:
- switch语句括号中的表达式以及case分支后的表达式可以是数字或字符串或布尔值;
- 在case后的各常量表达式的值不能相同,否则会出现错误;
- 在case后,允许有多个语句,可以不用
{}括起来,一般不建议这样做;- 各case和default子句的先后顺序可以变动,而不会影响程序执行结果;
- default子句可以省略不用;
if-else 语句与 switch 语句比较:
| if-else语句 | switch语句 |
|---|---|
| else不是必需的,可以只使用if语句;在多个if语句连续使用的时候,每一if都会被执行检测,即使已经找到了匹配(所以它的效率比switch语句要慢很多); | 可以使用default语句来处理所有case之外的情况;如果找到了一个匹配,相应的代码会被执行,然后break语句会停止执行switch语句中的其他分支(比同样功能的连续多个if语句性能要好); |
四、循环结构
循环结构是程序中一种很重要的结构。其特点是,在给定条件成立时,反复执行某程序段,直到条件不成立为止。给定的条件称为 循环条件,反复执行的程序段被称为 循环体 。JavaScript语言提供了多种循环语句,可以组成不同形式的循环结构。循环共有如下三种类型:
| for | while | do while |
|---|---|---|
如果需要将一段代码运行特定的次数,那么可以使用 for 循环(这也是最常用的一种循环)。在 for 循环中,检查的条件通常是一个计数器,这个计数器用来计算循环需要运行多少次。 | 如果不确定代码究竟要被执行多少次,可以使用 while 循环。这里的判断条件也可以使用计数器之外的形式,只要这个条件返回 true,对应的代码就会一直重复运行。 | do…while 循环和 while 循环非常类似,只有一处关键的区别:在 do...while 中,即使条件返回false,被包裹在花括号之中的语句也至少会运行一次。 |
4.1、for *
for 循环的语法结构:
for (初始化语句; 循环条件; 迭代增量) {
循环体
}
语法解读:
- 初始化:创建一个变量,然后赋值为0。这个变量通常被命名为
i,它起到计数器的作用;- 循环条件:循环会一直重复运行下去,直到计数器达到特定的数值;
- 迭代增量:每次循环执行完花括号内部的语句之后,计数器会加1;
我们来看一个示例:
for (var i = 0; i < 5; i++) {
console.log("Hello, world!");
}
上述示例中,程序会去执行初始化语句,此时i 的值为 0,然后去判断循环条件,如果 i < 5 为 true,则执行循环体的内容,打印 “Hello, world!”,然后再执行 i++,此时 i 的值为 2,到这里一次循环结束;第1次循环结束之后,初始化语句不再执行,初始化语句只执行一次,第2次循环直接继续判断循环条件,2 < 5 为 true,那么会执行循环体,再打印一次 “Hello, world!”,然后再执行迭代增量 i++,此时第2次循环结束。以此类推,当 i 的值为 5 的时候,判断循环条件 5 < 5 为 false,则跳出循环,故控制台会打印5次 “Hello, world!”。
tips:
for循环中,初始化、循环条件、迭代增量都是选择项,即可缺省,但
;不能省略;省略 初始化语句,表示不对循环控制变量赋初始值;
省略 循环条件,则不做其他处理时会进入死循环;
省略 迭代增量,则不对循环控制变量进行操作,这时可在语句体中加入修改循环控制变量的语句,比如在循环体中,做增量操作;
三个表达式都可以省略:
for (; ;) {}
- 初始化可以是设置循环变量的初值赋值表达式,也可以是其他表达式:
// 形式1 let sum = 0, i = 0; for (; i < 100; i++) { sum += i; } // 形式2 let sum, i; for(i = 0, sum = 0; i < 100; i++) { sum += i; }
初始化语句和迭代增量可以是一个简单表达式,也可以是一个逗号表达式;
循环条件一般是关系表达式或逻辑表达式,但也可以是数值表达式或字符表达式,只要其值为true,就执行循环体;
4.3、while
while 循环语法结构:
初始化语句
while(循环条件) {
循环体
迭代增量
}
语法解读:
while循环先去判断循环条件,如果结果为true,则执行循环体内容,否则结束循环。
我们来看一个示例,计算0~100的和:
var sum = 0, i = 0;
while (i <= 100) {
sum += i;
i++;
}
console.log('sum is ' + sum);
上述示例输出语句中为字符串的拼接,在控制台中,sum 变量会呈现其实际值,故而控制台呈现结果为:5050。
4.4、do…while
do…while 循环语法结构:
do {
循环体
}while(循环条件)
语法解读:do...while 循环会先去执行循环体的内容,再判断循环条件,如果循环条件为结果
true,再执行循环体内容,如果循环条件结果为false,则跳出循环。do...while 与 while 的区别在于,do...while 循环先执行循环体,再执行循环条件;while循环,先判断循环条件,再执行循环体;do...whilte 循环至少执行一次循环体。
同样地,我们来看一个使用 do…while 循环实现计算0~100的和的示例:
var sum = 0, i = 0;
do {
sum += i;
i++
} while (i <= 100);
console.log('sum is ' + sum);
4.5、循环嵌套
两个结论:
var i, j, str;
// 外层循环
for(i = 0; i < 2; i++) {
// 内层循环
for(j = 0; j < 3; j++) {
str = '';
str += 'i = ' + i + ' ';
str += 'j = ' + j;
console.log(str);
}
}
// 结论:外层循环执行一次,内层循环执行n次。
var i, j, str;
for(i = 0; i < 4; i++) {
for(j = 0; j < 5; j ++) {
str += '*';
}
str += '\n';
}
console.log(str);
// 结论:外层循环控制行数,内层循环控制列数。
// *****
// *****
// *****
// *****
循环语句通过嵌套可以解决一些有规律的复杂性的重复性工作,如我们在小学期间就学习过的“九九乘法表”。
let str = '';
for(let i = 1; i <= 9; i++) {
str = '';
for(let j = 1; j <= i; j++) {
str += '${j} * ${i} = ${i*j} ';
}
console.log(str);
}
输出结果为:
如果不了解循环运作的原理,一开始看到这样的结果必然不理解,实际在理解上,嵌套循环和在一个函数里再嵌套一个函数非常类似。可以把循环看成一个主流程上的点,主循环(外层的循环)形成一个环状的流程,循环的开始点和结束点和主流程相交,而子循环(内层的循环)又单独形成一个环,子循环的开始点和结束点又和外层循环上的某个点想交。每次子循环结束的时候,又会回到子循环内,进行新一轮的条件循环,当主循环的条件再次得到的值为真的时候,又会根据条件判断语句(如果有的话)是否决定再次进入子循环,以此类推。
tips:外层循环执行一次,内层循环执行n次;外层循环决定行数,内层循环决定列数;
接下来我们看几个利用循环嵌套打印星星的示例:
// 示例1
/*
* i = 1 space = 3 star = 1
*** i = 2 space = 2 star = 3
***** i = 3 space = 1 star = 5
******* i = 4 space = 0 star = 7
row = 4
space = row - i; star = 2 * i - 1
*/
let row = 4;
let spaces, stars, str = ``;
for(let i = 1; i <= row; i++) {
spaces = row - i;
stars = 2 * i - 1;
// 打印空格
for(let j = 1; j <= spaces; j++) {
str += ` `;
}
// 打印星星
for(let k = 1; k <= stars; k++) {
str += `*`;
}
str += `\n`;
}
console.log(str);
// 示例2
/*
* i = 1 space = 2 4 star = 1
*** i = 2 space = 1 2 star = 3
***** i = 3 space = 0 0 star = 5
*** i = 4 space = 1 2 star = 3
* i = 5 space = 2 4 star = 1
提示:
Math.ceil() 向上取整
Math.abs() 取绝对值
row = 5
space = Math.abs(Math.ceil(row/2) - i);
star = row - 2 * space
*/
let row = 5;
let spaces, stars, str = ``;
for(let i = 1; i <= row; i++) {
spaces = Math.abs(Math.ceil(row/2) - i);
stars = row - 2 * spaces;
// 打印空格
for(let j = 1; j <= spaces; j++) {
str += ` `;
}
// 打印星星
for(let k = 1; k <= stars; k++) {
str += `*`;
}
str += `\n`;
}
console.log(str);
五、流程控制 *
5.1、break
break 关键字通常用在循环语句和分支语句中。当break用于分支语句switch中时,可以使程序跳出switch而执行switch以后的语句。如果没有break关键字,则将成为一个死循环而无法退出。break在switch中的用法已在前面的介绍到,这里不再举例。
当 break 关键字用于do...while、for、while循环语句中时,可以使程序终止循环而执行循环后面的语句,通常break语句总是与if语句联在一起,即满足条件时退出。
// 示例1
for (var i = 0; i < 5; i++) {
if (i > 3) {
break;
}else {
console.log('idx = ' + i);
}
}
// 输出:
// idx = 0
// idx = 1
// idx = 2
// idx = 3
// 示例2
var citys = ["北京", "上海", "深圳", "重庆", "成都", "昆明", "西安"];
for (var i = 0; i < citys.length; i++) {
if (citys[i] === "成都") {
console.log("已经找到" + citys[i] + ",其在数组中的下标值为:" + i);
break;
}
}
// 输出:已经找到成都,其在数组中的下标值为:4
tips:在多层循环中,一个break关键字只向外跳出一层循环;
5.2、continue
continue 关键字的作用是跳过循环体中剩余的语句而执行下一次循环。continue语句只用在for、while、do...while循环体中,常与if条件语句一起使用,用来加速循环。
window.onload = function() {
for (var i = 0; i < 5; i++) {
if (i = 3) { // 如果i的值为3,则跳出这一次循环,执行下一次循环
continue;
}
console.log(i);
}
}
上述示例中,当i的值为3时,跳出本次循环,不再打印,继续执行下一次循环,故而控制台输出:0,1,2,4。
六、课后练习
1. 大家都知道,男大当婚,女大当嫁。那么女方家长要嫁女儿,当然要提出一定的条件(if|switch)
高:180cm以上; 富:1000万以上; 帅:500以上;
如果这三个条件同时满足,则:'我一定要嫁给他'
如果三个条件有为真的情况,则:'嫁吧,比上不足,比下有余。'
如果三个条件都不满足,则:'不嫁!'
2. 从键盘输入小明的期末成绩(if|switch)
当成绩为100时,'奖励一辆BMW'
当成绩为[80-99]时,'奖励一台iphone15s'
当成绩为[60-80]时,'奖励一本参考书'
其他时,什么奖励也没有
3. 从键盘输入电影类型(if|switch)
当类型为"恐怖"时,返回你所知道的恐怖电影
当类型为"喜剧"时,返回你所知道的喜剧电影
当类型为"科幻"时,返回你所知道的科幻电影
当类型为"动作"时,返回你所知道的动作电影
4. 打印输出 "9*9" 乘法表(for)
5. 计算 "50~100" 的和(for|do...while|while)
6. 输入月、日,计算是今年的第几天,2月统一为28天(switch)