1.`if`与`else`:设置岔路口
第1讲说过,代码从上到下依次执行。条件语句在这条流程上设置岔路口。写if (条件) { … },只有括号里的条件为真时才执行花括号里的代码,为假就跳过。如果条件为假时另有要做的事,就在后面接上else { … }。两条路中只会恰好执行一条。
条件的位置要写结果为true或false的表达式。第2讲的布尔值正是在这里派上用场。age >= 19在age大于等于19时为true,否则为false。先用console.log把条件表达式打印出来,就能预先知道条件语句会走哪一边;条件语句没有按预想运行时,这有助于找到原因。
花括号里的代码缩进两格,让人一眼看出“这段代码属于这个条件”。运行环境不看缩进,而是靠花括号区分;人却是靠缩进来读结构的。缩进错乱的代码会误导读者,所以要始终对齐。即使花括号里只有一行代码,也最好不要省略花括号,这样以后添加代码时不容易出错。
const age = 17;
console.log(age >= 19);
if (age >= 19) {
console.log("成人票");
} else {
console.log("青少年票");
}false 青少年票
2.`else if`:多个分支从上往下依次检查
分支有三条以上时,就接上else if。运行环境从上往下逐个检查条件,只执行第一个为真的分支,其余的全部跳过。如果没有任何条件为真,就执行最后的else。所以else负责的是“上面所有情况之外的全部剩余情况”。
因为“只执行第一个为真的”这条规则,条件的顺序很重要。如果按分数评等级,就必须从高的标准开始依次检查。95分既满足score >= 90,也满足score >= 80;如果先写80的条件,95分就会得到B。从高标准往下走,后面的条件就可以默认“前面的条件已经为假”,也就不必像score >= 80 && score < 90那样把范围的两头都写出来。
写条件语句之前先整理成表格,就容易发现漏掉的区间和重叠的区间。像下面的例子那样,定好“90以上A,80以上B,70以上C,其余F”,照着表格从上往下搬过去即可。等级标准只是示例,实际标准因学校、公司而异。
const score = 85;
if (score >= 90) {
console.log("A");
} else if (score >= 80) {
console.log("B");
} else if (score >= 70) {
console.log("C");
} else {
console.log("F");
}B
// 顺序写错的例子
const s = 95;
if (s >= 80) {
console.log("B");
} else if (s >= 90) {
console.log("A");
}B
3.比较运算符与`===`和`==`
比较两个值的运算符有:大于(>)、小于(<)、大于等于(>=)、小于等于(<=)、等于(===)、不等于(!==)。结果总是true或false。比较是否相等时如果只写一个=,就不是比较,而成了放入值的赋值,请务必注意。这个错误非常常见,有时还会不报错、悄悄地出现离谱的行为。
JavaScript里的“等于”有两种。===(严格相等)要求数据类型和值都相同才是true。==(宽松相等)在数据类型不同时,会先做第2讲看到的隐式类型转换再比较。所以1 == "1"是true,0 == ""也是true。由于规则复杂、难以预料,几乎所有编程指南和检查工具都建议只用===和!==。本课程也始终使用===。
字符串之间也可以比较。===要求一个字符都不差,所以"小明" === "小明 "(末尾多一个空格)是false。比较用户输入时,常常因为前后的空格而对不上,第7讲会学习用trim整理的方法。对字符串使用<、>时,会按接近字典顺序的字符编码顺序比较;就像"10" < "9"是true一样,看起来像数字的字符串会被比得一塌糊涂,所以要先转成数字。
==在类型转换后才比较,结果会出乎意料console.log(3 > 2, 3 >= 3, 3 !== 3);
console.log(1 === "1", 1 == "1");
console.log(0 == "", 0 === "");
console.log(null == undefined, null === undefined);true true false false true true false true false
console.log("小明" === "小明 ");
console.log("10" < "9", 10 < 9);
console.log(Number("10") < Number("9"));false true false false
| 运算符 | 含义 | 例子 | 结果 |
|---|---|---|---|
=== | 数据类型和值都相同 | 5 === 5 | true |
!== | 不相等(严格) | 5 !== "5" | true |
> / < | 大于 / 小于 | 3 < 2 | false |
>= / <= | 大于等于 / 小于等于 | 60 >= 60 | true |
== | 类型转换后相等(不使用) | 1 == "1" | true |
4.逻辑运算符:并且`&&`、或者`||`、不是`!`
要把多个条件组合起来,就用逻辑运算符。A && B只有A和B都为真时才为真;A || B只要有一个为真就为真。!A把真和假颠倒过来。“是会员并且买满3万韩元”用&&,“是会员或者买满3万韩元”用||。日常说话时“并且”“或者”用得比较随意,所以用语言定好条件后,最好再确认一次到底是哪一种。
&&和||只看左边就能确定答案时,就不再计算右边。在A && B中,A为假时不管B如何结果都是假,所以不看B;在A || B中,A为真时不看B。利用这一点写成user !== null && user.age >= 19,user为null时就不会读取右边,从而避开第2讲见过的TypeError。如果调换顺序,这层保护就没有了。
在一个表达式里混用&&和||时,&&先计算。不过,与其背下这个优先级来用,不如用括号把意图表达出来,安全得多。表示范围时,如果像数学那样写成10 <= x <= 20,虽然不会报错,却不会按本意运行。一定要拆成两个比较来写,比如x >= 10 && x <= 20。
const isMember = false;
const total = 32000;
console.log(isMember && total >= 30000);
console.log(isMember || total >= 30000);
console.log(!isMember);false true true
10 <= x先变成true,true <= 20再被转换成1 <= 20,于是为真const x = 25;
console.log(10 <= x <= 20); // 不会按本意运行
console.log(x >= 10 && x <= 20);true false
5.`truthy`与`falsy`:不是布尔值也能当条件
在if的括号里放入不是布尔值的值,也不会报错。JavaScript会把那个值转成真或假来判断。被当作假的值(falsy)是固定的几个:false、0、-0、0n、空字符串""、null、undefined、NaN。不在这个名单里的值全部被当作真(truthy)。空数组[]和空对象{}、文字"0"和"false"也都是truthy,这一点常常让人搞混。
得益于这个性质,可以把“如果有值”简短地写成if (name) { … }。但这里有个陷阱。在个数、金额中,0是正常的值,却是falsy。用if (stock)检查库存为0件的商品,“没有库存信息”和“库存为0件”就会进入同一条分支。这也是AI写的代码里常见的错误。
所以,当你清楚自己要确认什么时,就把条件写具体。要看值是否为空,写stock === null或stock === undefined;要看是否大于0,写stock > 0;要看是否为空字符串,写name === ""。想知道某个值是不是truthy,可以用Boolean(值)直接确认。
"0"和空数组是truthyconsole.log(Boolean(0), Boolean(""), Boolean(null));
console.log(Boolean(NaN), Boolean(undefined));
console.log(Boolean("0"), Boolean("false"));
console.log(Boolean([]), Boolean(-1));false false false false false true true true true
const stock = 0;
if (stock) {
console.log("可以购买");
} else {
console.log("没有库存信息?"); // 明明是0件却来到这里
}
if (stock === null) {
console.log("没有库存信息");
} else if (stock > 0) {
console.log("可以购买");
} else {
console.log("已售罄");
}没有库存信息? 已售罄
6.边界值:条件语句总在边界上出错
条件语句的错误大多发生在边界上。把“60分及以上及格”写成score > 60,60分就会不及格。只用59分和61分测试,是发现不了这个错误的。所以检查条件语句时,一定要放入紧挨边界下方、边界本身、紧挨边界上方的值。再加上最小值(0)和最大值(100),以及不该出现的值(负数、超过100),大部分错误都会暴露出来。
从用语言制定规则时起,就要把边界说清楚。“满19岁及以上”“满3万韩元及以上包邮”“超过10件打折”中,“及以上”是>=,“超过”是>,“及以下”是<=,“未满”是<。需求如果像“从3万韩元起”这样含糊,写代码之前就该确认正好3万韩元算哪一边。拜托AI写代码时,用语言把边界写清楚,结果也会准确得多。
把要检查的值整理成表格,它就直接成了测试用例。本课程练习场的评分器做的也是同样的事:放入事先定好的输入,与期望值比较。第5讲学了函数,就能更轻松地编写这样的测试;第10讲则会用这种方法检验AI写的代码。
| 输入 | 选择的理由 | 期望结果 | 错写成`score > 60`时 |
|---|---|---|---|
59 | 紧挨边界下方 | 不及格 | 不及格 |
60 | 边界本身 | 及格 | 不及格(发现错误) |
61 | 紧挨边界上方 | 及格 | 及格 |
0 / 100 | 最小值、最大值 | 不及格 / 及格 | 不及格 / 及格 |
-5 / 120 | 不该出现的值 | 按无效分数处理 | 不及格 / 及格(没有检查) |
const orders = [[29999, false], [30000, false], [0, true]];
for (const [total, isMember] of orders) {
let fee = 3000;
if (total >= 30000 || isMember) {
fee = 0;
}
console.log(total, isMember, fee);
}29999 false 3000 30000 false 0 0 true 0
- 第1步 找边界:金额的边界是30,000韩元,而且是“满……及以上”,所以用
>=。是否会员有真、假两种。 - 第2步 挑测试值:非会员选29,999韩元和30,000韩元,再选一个会员的0韩元(看金额极小时会员是否也免运费)。
- 第3步 写条件:
total >= 30000 || isMember为真就是0,否则是3000。 - 验算:只有29,999韩元的非会员应为3,000韩元,其余都应为0韩元。如果30,000韩元得到3,000韩元,就是错用了
>。
for … of是第4讲要学的循环,像[29999, false]这样用方括号括起来的列表是第6讲要学的数组。const [total, isMember]是把列表的第一个、第二个值依次放进两个名字的语法。现在只要看懂“把情况一个个取出来,放进同一个条件语句试一试”就可以了。📌 要点总结
if、else if、else从上往下检查,只执行第一个为真的分支——顺序很重要- 比较是否相等时始终用
===、!==——==在类型转换后才比较,难以预料 &&是全部为真,||是有一个为真,!是取反;范围要拆开写成x >= 10 && x <= 20falsy包括false、0、""、null、undefined、NaN等;0是正常值时要把条件写具体- 条件语句要用边界下方、边界本身、边界上方、两端的值和无效值来测试
🧪 代码练习
用条件语句完成函数的练习。评分器会放入包括边界值在内的多种输入来试。
代码只在本浏览器内的隔离环境中运行,不会发送到服务器。无法访问网络,超过2秒会自动停止。改过的代码只保存在此浏览器中。按 Ctrl+Enter(⌘+Enter)运行,Tab 键输入两个空格(先按 Esc 再按 Tab 可跳到下一项)。
浏览器脚本未开启,无法运行代码,但题目、初始代码、自动检查项和参考答案都可以直接阅读。
1判断是否成年
isAdult(age)在年龄age(数字)满19岁及以上时返回true,否则返回false。
isAdult(18)期望值falseisAdult(19)期望值trueisAdult(20)期望值trueisAdult(0)期望值false
💡 提示
“及以上”包含边界本身。放入19试试看。
查看参考答案
function isAdult(age) {
return age >= 19;
}
2按分数评等级
grade(score)接收0~100分的分数,90及以上返回"A",80及以上返回"B",70及以上返回"C",其余返回"F"。
grade(100)期望值"A"grade(90)期望值"A"grade(89)期望值"B"grade(70)期望值"C"grade(69)期望值"F"grade(0)期望值"F"
💡 提示
从高标准开始检查。遇到return函数就立即结束,后面的条件不会再看。
查看参考答案
function grade(score) {
if (score >= 90) {
return "A";
} else if (score >= 80) {
return "B";
} else if (score >= 70) {
return "C";
} else {
return "F";
}
}
3计算运费
这是虚构的网店规则。shippingFee(total, isMember)在订单金额total满30000及以上或者是会员(isMember为true)时返回0,否则返回3000。但订单金额在0及以下(空订单)时,不论是否会员都返回0。
shippingFee(29999, false)期望值3000shippingFee(30000, false)期望值0shippingFee(5000, true)期望值0shippingFee(0, false)期望值0shippingFee(1, false)期望值3000
💡 提示
先把空订单筛掉,再检查total >= 30000 || isMember。
查看参考答案
function shippingFee(total, isMember) {
if (total <= 0) {
return 0;
}
if (total >= 30000 || isMember) {
return 0;
}
return 3000;
}
4门票价格与无效输入
这是虚构的博物馆门票。ticketPrice(age)在未满7岁时返回0,7岁及以上、未满19岁返回3000,19岁及以上、未满65岁返回6000,65岁及以上返回0。年龄为负数或不是数字(typeof age !== "number")时返回null。
ticketPrice(6)期望值0ticketPrice(7)期望值3000ticketPrice(19)期望值6000ticketPrice(65)期望值0ticketPrice(-1)期望值nullticketPrice("20")期望值null
💡 提示
在最前面检查typeof age !== "number" || age < 0,后面的条件就只处理正确的数字了。“未满”是<。
查看参考答案
function ticketPrice(age) {
if (typeof age !== "number" || age < 0) {
return null;
}
if (age < 7) {
return 0;
} else if (age < 19) {
return 3000;
} else if (age < 65) {
return 6000;
}
return 0;
}
🤖 可以这样问 AI
复制后把 [ ] 部分换成你的情况。不要直接相信回答,请与正文对照核实。
把条件规则写成代码之前
我想把下面的规则写成JavaScript条件语句。在写代码之前,先就边界值(及以上、超过、及以下、未满)含糊的地方向我提问,再把所有情况整理成“输入—期望结果”表格,让表格的每一行都能成为一个测试用例。规则:[规则说明]
审查AI写的条件语句时
请逐一检查下面的条件语句里是否有:(1) 因为`else if`的顺序而永远到达不了的分支,(2) 使用了`==`,(3) 把0或空字符串当作`falsy`误筛掉的地方,(4) 边界值与规则不符的地方。每个问题都请附上能暴露它的输入值。规则:[规则] 代码:[粘贴代码]
想练习对真假值的感觉时
请出10道关于JavaScript的`truthy`、`falsy`以及`===`/`==`比较的预测题。每道题都问`if (值)`会走哪条分支,先把答案藏起来,等我回答后再连同理由一起告诉我。
🧰 相关工具
可以当场检查、整理本讲涉及的 JSON、正则表达式和文本的工具。请不要粘贴真实的个人信息或密码。
- MDN Web Docs — JavaScript指南(Guide)中的控制流与错误处理(if...else)、表达式与运算符
- MDN Web Docs — Falsy、Truthy术语说明,相等性判断(Equality comparisons and sameness)
- 软件测试入门书中关于边界值分析的一般内容
达成全部学习目标后,请点击完成。
此浏览器无法保存记录,仅在当前页面显示。