DRAFT 《现代 JavaScript 教程》前端基础系列 03:语言进阶——类型转换、运算符与控制流
约 6942 字大约 23 分钟
2026-04-17
本篇我们将深入探讨 JavaScript 中类型转换的规则,探索基础的数学及逻辑运算符,并学习如何使用条件分支控制代码的走向。掌握这些机制将帮助你避免因隐式转换带来的陷阱,并编写出更加严谨的代码。
【本篇核心收获】
- 理解 JavaScript 中的三种基本类型转换(字符串、数字、布尔值)及其陷阱。
- 掌握算术运算符、一元运算符与赋值运算符的常见特性及优先级。
- 熟悉各种值的比较规则,特别是与
null和undefined比较时的特例。 - 灵活运用
if...else语句及三元运算符?进行条件分支控制。 - 深入理解逻辑运算符
||(或)、&&(与)、!(非)的短路求值特性。
类型转换:揭开隐式转换的面纱
在实际开发中,运算符和函数往往会自动将赋予它们的值转换为正确的类型。例如,alert 会自动将任何值转换为字符串以进行显示,而算术运算符则会将值转换为数字。但在某些场景下,我们需要手动且显式地转换值的类型。
注:本节暂不讨论
object(对象)类型,仅聚焦于原始值的转换。
字符串转换 (String Conversion)
背景与认知: 当我们需要一个值的字符串形式时,就会发生字符串转换。最常见的场景就是输出或者显示内容。
落地操作:
你可以通过显式调用 String(value) 来将值转换为字符串。
let value = true;
alert(typeof value); // 输出: "boolean"
// 显式转换为字符串
value = String(value);
alert(typeof value); // 输出: "string"
// 此时,原来的布尔值 true 变成了一个字符串 "true"验证与现象:
字符串转换的规则非常直观。false 变成 "false",null 变成 "null",依此类推。
数字型转换 (Numeric Conversion)
背景与认知: 在算术函数和表达式中,通常会自动进行数字型转换。
落地操作:
例如,当把除法 / 用于非数字类型时,会触发自动转换:
alert("6" / "2");
// 输出: 3
// 解析: string 类型的值被自动转换成 number 类型后进行计算当然,我们也可以使用 Number(value) 显式地将值转换为数字:
let str = "123";
let num = Number(str); // 显式转换为 number 类型,值为 123避坑提示: 当我们从 HTML 表单等文本源读取值,且期望它是一个数字时,往往需要这种显式转换。如果字符串不是一个有效的数字,转换的结果将是
NaN(Not a Number)。
let age = Number("an arbitrary string instead of a number");
alert(age); // 转换失败,输出 NaN数字转换规则一览表:
| 值 | 转换结果 |
|---|---|
undefined | NaN |
null | 0 |
true / false | 1 / 0 |
string | 自动去掉首尾空白字符(空格、换行符 \n、制表符 \t 等)。 如果剩余字符串为空,则结果为 0。 如果剩余字符串包含非数字字符,则结果为 NaN。 |
验证案例:
alert(Number(" 123 ")); // 123 (首尾空白被忽略)
alert(Number("123z")); // NaN (遇到了非数字字符 "z")
alert(Number(true)); // 1
alert(Number(false)); // 0避坑提示: 请特别留意
null和undefined的区别:null转换为0,而undefined转换为NaN。
布尔型转换 (Boolean Conversion)
背景与认知: 这是最简单的一种转换,通常发生在逻辑运算(如条件判断)中,也可以通过调用 Boolean(value) 显式转换。
转换规则:
- 假值 (Falsy values):直观上为“空”或“无”的值,如
0、空字符串""、null、undefined和NaN,都会变成false。 - 真值 (Truthy values):除了假值之外的所有值,都会变成
true。
验证案例:
alert(Boolean(1)); // true
alert(Boolean(0)); // false
alert(Boolean("hello")); // true
alert(Boolean("")); // false避坑提示:包含 0 的字符串
"0"也是true!
在某些语言(如 PHP)中,"0"被视为false。但在 JavaScript 中,任何非空的字符串总是true。即使是只包含一个空格的字符串" ",也是true。
alert(Boolean("0")); // true
alert(Boolean(" ")); // 空格也是非空字符串,所以是 true模块小结: 类型转换分为三种:字符串转换(直观的文本化)、数字转换(常用于数学运算,注意
undefined变NaN),以及布尔转换(记住五种假值即可)。
基础运算符与数学运算
这一节我们将从学校学过的加减乘除开始,逐步过渡到 JavaScript 特有的一些运算符特性。
术语速览:一元、二元与运算元
- 运算元 (Operand):运算符应用的对象(有时也叫“参数”)。例如
5 * 2中的5和2。 - 一元运算符 (Unary Operator):只对一个运算元起作用。例如一元负号
-可以翻转符号:let x = 1; x = -x; // x 变成 -1。 - 二元运算符 (Binary Operator):作用于两个运算元。例如减法:
y - x。
常见数学运算
JavaScript 支持基本的数学运算:加 +、减 -、乘 *、除 /。此外,还有两个稍显特别的:
取余 % (Remainder)a % b 的结果是 a 整除 b 之后的余数。
alert( 5 % 2 ); // 1 (5 除以 2 的余数是 1)
alert( 8 % 3 ); // 2求幂 ** (Exponentiation)a ** b 表示求 a 的 b 次方。它也支持非整数(如求平方根)。
alert( 2 ** 3 ); // 8 (2的3次方)
alert( 4 ** (1/2) ); // 2 (相当于求 4 的平方根)字符串连接:二元运算符 +
认知与现象: 通常 + 用于数字求和。但只要其中一个运算元是字符串,+ 就会将两个运算元进行字符串拼接。
alert( '1' + 2 ); // "12"
alert( 2 + '1' ); // "21"深入拆解:执行顺序很重要
运算符是按顺序工作的,如果存在连续的加法,注意先后顺序!
alert( 2 + 2 + '1' ); // "41" (前两个 2 是数字相加得 4,然后再与 '1' 拼接)
alert( '1' + 2 + 2 ); // "122" (第一个是字符串,所以后续的 2 都被视为字符串拼接)避坑提示: 只有
+支持字符串拼接!其他算术运算符(-、/、*)总是将运算元隐式转换为数字后进行计算。
alert( 6 - '2' ); // 4 (字符串 '2' 被转换为数字)
alert( '6' / '2' ); // 3数字转化:一元运算符 +
认知与落地: 除了二元的加法,+ 还可以作为一元运算符使用。如果运算元不是数字,一元加号 + 会强制将其转化为数字,效果等同于 Number(...),但更简短。
alert( +true ); // 1
alert( +"" ); // 0
// 常用于将字符串变量快速转化为数字进行求和
let apples = "2";
let oranges = "3";
// 在二元加号合并之前,一元加号先将它们转为数字
alert( +apples + +oranges ); // 5运算符优先级 (Operator Precedence)
当表达式中有多个运算符时,执行顺序由优先级决定。例如乘法优先级高于加法。若想改变顺序,请使用圆括号 (),圆括号拥有最高优先级。
注意:一元运算符(如一元加号 +,优先级 15)的优先级通常高于二元运算符(如加号 +,优先级 12)。这也是为什么 +apples + +oranges 中一元加号会先起作用。
赋值运算符 = 及其返回值
赋值符号 = 也是一个运算符(优先级为 2,非常低)。这解释了为什么在 x = 2 * 2 + 1 中,计算完成后才会执行赋值。
深度拆解:赋值会返回一个值
在 JavaScript 中,所有运算符都会返回一个值。语句 x = value 不仅将 value 写入 x,还会返回这个value。
let a = 1;
let b = 2;
// b + 1 的结果赋给 a(a 变成 3),同时赋值表达式本身返回 3,然后再被 3 减去
let c = 3 - (a = b + 1);
alert( a ); // 3
alert( c ); // 0注:了解此机制即可,实际开发中为了可读性,强烈不建议写这种复杂的嵌套赋值代码。
链式赋值 (Chaining assignments)
赋值运算支持从右向左的链式操作:
let a, b, c;
a = b = c = 2 + 2; // a, b, c 都会被赋值为 4原地修改 (Modify-in-place) 与自增/自减
原地修改
当我们需要对变量进行运算并将结果存回该变量时,可以使用如 +=、*= 等缩写。
let n = 2;
n += 5; // 等同于 n = n + 5; 现在 n 是 7
n *= 2; // 等同于 n = n * 2; 现在 n 是 14自增 (++) / 自减 (--)
用于将变量加一或减一。注意:它们只能应用于变量,不能应用于具体的数值(如 5++ 会报错)。
- 前置形式 (
++counter):先自增,然后返回新值。 - 后置形式 (
counter++):先自增,但返回旧值(自增前的值)。
let counter1 = 1;
alert( ++counter1 ); // 2 (前置,返回新值)
let counter2 = 1;
alert( counter2++ ); // 1 (后置,返回旧值)
alert( counter2 ); // 2 (此时变量本身已经加一)建议:为了代码可读性,推荐使用“一行一个行为”的模式,避免将
++或--与其他复杂表达式混写在一行中。
逗号运算符 , (Comma Operator)
这是一个少见且优先级极低(比 = 还低)的运算符。它允许在一行内执行多个表达式,用逗号隔开,但只会返回最后一个表达式的结果。
// 注意括号,因为逗号优先级极低
let a = (1 + 2, 3 + 4);
// 1 + 2 会执行但结果被丢弃;然后执行 3 + 4,最后返回 7 赋给 a
alert( a ); // 7注:常用于
for循环中的一些简写技巧,但平时应尽量少用以保证代码可读性。
模块小结: 本节我们学习了基础数学运算,认识了字符串的拼接特性(
+),掌握了一元+的快速转型技巧,以及++、--前置与后置的区别。
核心任务(练习题)
任务:后置运算符和前置运算符
以下代码中变量 a、b、c、d 的最终值分别是多少?
let a = 1, b = 1;
let c = ++a; // ?
let d = b++; // ?解决方案:
a = 2(无论前置后置,自身都会加1)b = 2c = 2(前置++a返回的是加 1 后的新值)d = 1(后置b++返回的是加 1 前的旧值)
任务:赋值结果
下面这段代码运行完成后,代码中的 a 和 x 的值是多少?
let a = 2;
let x = 1 + (a *= 2);解决方案:
a = 4(执行了a *= 2,即a = a * 2)x = 5(赋值表达式(a *= 2)返回了赋值的结果4,然后计算1 + 4)
任务:类型转换
写出下面这些表达式的结果:
"" + 1 + 0
"" - 1 + 0
true + false
6 / "3"
"2" * "3"
4 + 5 + "px"
"$" + 4 + 5
"4" - 2
"4px" - 2
" -9 " + 5
" -9 " - 5
null + 1
undefined + 1
" \t \n" - 2解决方案:
"" + 1 + 0 = "10" // (1) 空字符串开始,后续全视为字符串拼接: "1" + 0 = "10"
"" - 1 + 0 = -1 // (2) 减法强制转数字:空字符串 "" 转为 0。 0 - 1 + 0 = -1
true + false = 1 // 布尔值参与算术运算,true为1,false为0
6 / "3" = 2 // 字符串 "3" 被转为数字 3
"2" * "3" = 6 // 乘法同理,都转为数字
4 + 5 + "px" = "9px" // 顺序执行:先算 4+5=9,然后 9 与 "px" 拼接
"$" + 4 + 5 = "$45" // 顺序执行:开头是字符串,后续的加法全变拼接
"4" - 2 = 2 // 减法转数字
"4px" - 2 = NaN // 减法转数字,但 "4px" 无法转换为有效数字,得到 NaN
" -9 " + 5 = " -9 5" // 加号拼接字符串
" -9 " - 5 = -14 // 减号转数字,忽略首尾空格变为 -9, -9 - 5 = -14
null + 1 = 1 // 算术运算中 null 转为数字 0
undefined + 1 = NaN // 算术运算中 undefined 转为数字 NaN,NaN与任何数相加还是 NaN
" \t \n" - 2 = -2 // 纯空白字符字符串转为数字 0, 0 - 2 = -2任务:修正加法
下面这段代码本意是要求用户输入两个数字并显示它们的总和。但当用户输入 1 和 2 时,输出却是 12。请修正它,使结果为 3。
let a = prompt("First number?", 1);
let b = prompt("Second number?", 2);
alert(a + b); // 12解决方案:
原因是 prompt 无论用户输入什么,都会返回一个字符串类型(即 "1" 和 "2"),使用 + 会导致字符串拼接。
我们需要在相加前将它们转换为数字。最简洁的方法是在 prompt 之前使用一元运算符 +:
let a = +prompt("First number?", 1);
let b = +prompt("Second number?", 2);
alert(a + b); // 3值的比较:真理与假象
在 JavaScript 中,比较运算符(>, <, >=, <=, ==, !=)总是返回布尔值 true 或 false。
字符串比较 (字典顺序)
规则: 字符串是按字符(严格说是按 Unicode 编码顺序)逐个逐位进行比较的,类似于查字典。
alert( 'Z' > 'A' ); // true (Z 的编码大于 A)
alert( 'Glow' > 'Glee' ); // true (前两个字符相同,第3个字符 'o' 大于 'e')注:小写字母的 Unicode 编码大于大写字母,所以
'a' > 'A'为true。
不同类型间的比较
规则: 当对不同类型的值进行比较大小时,JavaScript 会首先将它们隐式转换为数字 (number) 然后再做判定。
alert( '2' > 1 ); // true (字符串 '2' 变成了数字 2)
alert( '01' == 1 ); // true
alert( true == 1 ); // true (true 变成了数字 1)
alert( false == 0 ); // true严格相等 (===) 与非严格相等 (==)
背景与问题: 普通的相等检查 == 在比较前会进行类型转换。这就导致它无法区分 0 和 false,甚至无法区分空字符串和 false:
alert( 0 == false ); // true (false 会被转换为 0)
alert( '' == false ); // true ('' 和 false 都会被转换为 0)落地操作:
如果我们想严格区分数据类型,必须使用严格相等运算符 ===(以及严格不相等 !==)。
规则: === 在进行比较时绝对不会做任何类型转换。如果类型不同,立刻返回 false。
alert( 0 === false ); // false (数字和布尔值类型不同,不相等)null 和 undefined 比较的特例
这部分是 JavaScript 比较逻辑中著名的“陷阱区”。
1. 严格相等 === 下:
类型不同,显然不相等。
alert( null === undefined ); // false2. 非严格相等 == 下:
这是一条硬性特例:null 和 undefined 在 == 比较下就像一对好基友,它们只等于彼此,不等于任何其他值(也不发生转型)。
alert( null == undefined ); // true
alert( null == 0 ); // false (null 不等于 0)3. 数学比较符 <, >, <=, >= 下:
此时,它们会被强制转换为数字:null 转为 0,undefined 转为 NaN。
著名的奇怪现象剖析:nullvs0
alert( null > 0 ); // false (null转为0,0 > 0 是错的)
alert( null == 0 ); // false (相等性检查特例,null只等于undefined)
alert( null >= 0 ); // true (null转为0,0 >= 0 是对的)现象解释:相等性检查 == 的机制与大小比较符 >= 的机制是完全独立的。
避坑指南:
- 尽量使用严格相等
===。 - 如果一个变量的值可能是
null或undefined,绝对不要用它直接与数字进行>=,<,>,<=比较。应先单独判空。
模块小结: 比较运算始终返回布尔值。字符串按字典序比较;不同类型通常先转为数字再比较(除非使用
===);牢记null和undefined在==时的特例,并防范null在大小比较时的诡异行为。
核心任务(练习题)
任务:值的比较
写出以下表达式的执行结果:
5 > 4
"apple" > "pineapple"
"2" > "12"
undefined == null
undefined === null
null == "\n0\n"
null === +"\n0\n"解决方案:
5 > 4 // true
"apple" > "pineapple" // false (字典序比较,'a' 比 'p' 小)
"2" > "12" // true (字典序比较首字符:'2' 大于 '1')
undefined == null // true (特例:它们在非严格模式下互等)
undefined === null // false (严格模式:类型不同)
null == "\n0\n" // false (特例:null只等于undefined,不等于其他任何值)
null === +"\n0\n" // false (严格模式:类型不同)条件分支:控制代码的走向 (if 和 ?)
有时候我们需要根据不同的条件让程序执行不同的任务。
if 语句与布尔转换
背景与认知: if(...) 会计算括号内的条件表达式。如果计算结果为 true(或能转换为真值),则执行对应的代码块。
let year = 2015;
// 只有当条件成立时,才会执行大括号里的内容
if (year == 2015) {
alert( "That's correct!" );
}隐式布尔转换:if (...) 语句会自动将圆括号内的结果转为布尔型。结合前面学过的知识:
- 假值 (Falsy):
0,"",null,undefined,NaN。如果条件是这些,代码块不会执行。 - 真值 (Truthy):其他所有值(如
1,"hello","0"等)。如果条件是这些,代码块会执行。
if (0) { /* 这里面的代码永远不会执行 */ }
if (1) { /* 这里面的代码一定会执行 */ }else 与 else if 分支
当 if 条件不成立时,可以提供一个可选的 else 代码块作为备用方案。如果有多重条件,可以使用 else if 进行串联判断。
let year = prompt('In which year was ECMAScript-2015 specification published?', '');
if (year < 2015) {
alert( 'Too early...' ); // 条件 1
} else if (year > 2015) {
alert( 'Too late' ); // 条件 2
} else {
alert( 'Exactly!' ); // 上述条件都不满足时执行
}条件运算符(三元运算符) ?
背景与认知: 有时我们需要根据条件来给一个变量赋值。虽然可以用 if...else 解决,但代码略显冗长。
let accessAllowed;
let age = 20;
// 使用 if...else 赋值
if (age > 18) {
accessAllowed = true;
} else {
accessAllowed = false;
}落地操作:
我们可以使用更简洁的“问号”运算符 ?(也称三元运算符,因为它需要三个操作数)。
语法: let result = condition ? value1 : value2;
如果 condition 为真,返回 value1;否则返回 value2。
// 使用三元运算符简写上面的代码
let age = 20;
let accessAllowed = (age > 18) ? true : false;
// 注意:比较运算符 > 的优先级高于 ?,所以条件外的括号可省略。
// 实际上这里可以直接写 let accessAllowed = age > 18;多个 ? 的链式调用:
我们可以串联多个 ? 来处理类似 else if 的多重逻辑,虽然代码紧凑,但也需注意可读性。
let age = prompt('age?', 18);
// 类似 else if 的链条检查
let message = (age < 3) ? 'Hi, baby!' :
(age < 18) ? 'Hello!' :
(age < 100) ? 'Greetings!' :
'What an unusual age!';
alert( message );避坑提示:切勿滥用
?替代if。
仅当你需要根据条件返回一个值时使用?。如果你的目的是根据条件执行不同的代码块(例如弹出不同的alert,而不关心返回值),请老老实实使用if...else,以保证代码的垂直可读性。
模块小结:
if语句依赖隐式布尔转换控制代码走向;else if负责多重分支;三元运算符?则是实现“条件赋值”的优雅语法糖,但不应被用作执行代码块的快捷方式。
核心任务(练习题)
任务:if(值为 0 的字符串)
alert 弹窗会出来吗?
if ("0") {
alert( 'Hello' );
}解决方案:
是的,它会。在 JavaScript 中,任何非空字符串(包括 "0" 和 " ")的布尔逻辑值都是 true。
任务:JavaScript 的名字
使用 if..else 结构,实现提问 “What’s the “official” name of JavaScript?” 的代码。
如果访问者输入了 “ECMAScript”,输出提示 “Right!”,否则输出 “You don’t know? “ECMAScript”!”
解决方案:
let value = prompt('What is the "official" name of JavaScript?', '');
if (value == 'ECMAScript') {
alert('Right!');
} else {
alert("You don't know? ECMAScript!");
}任务:显示符号
编写代码通过 prompt 获取一个数字并用 alert 显示结果:如果数字大于 0,显示 1;小于 0,显示 -1;等于 0,显示 0。
解决方案:
let value = prompt('Type a number', 0);
if (value > 0) {
alert( 1 );
} else if (value < 0) {
alert( -1 );
} else {
alert( 0 );
}任务:使用 '?' 重写 'if' 语句
使用条件运算符 '?' 重写下面的代码:
let result;
if (a + b < 4) {
result = 'Below';
} else {
result = 'Over';
}解决方案:
let result = (a + b < 4) ? 'Below' : 'Over';任务:使用 '?' 重写 'if..else' 语句
使用多个三元运算符 '?' 重写下面的代码:
let message;
if (login == 'Employee') {
message = 'Hello';
} else if (login == 'Director') {
message = 'Greetings';
} else if (login == '') {
message = 'No login';
} else {
message = '';
}解决方案:
let message = (login == 'Employee') ? 'Hello' :
(login == 'Director') ? 'Greetings' :
(login == '') ? 'No login' :
'';逻辑运算符:灵活的短路魔法
JavaScript 中主要有三种逻辑运算符:||(或),&&(与),!(非)。
与传统语言不同,JavaScript 的逻辑运算符不仅可以处理布尔值,还可以处理任意类型的值,并且它们的返回值也不局限于布尔值。
||(逻辑或 OR)
传统认知: 只有两边都是 false 时才返回 false,只要有一个是 true,结果就是 true。常用于 if 条件中检查是否满足任一条件。
let hour = 12;
let isWeekend = true;
// 如果时间不对 或者 是周末,就关门
if (hour < 10 || hour > 18 || isWeekend) {
alert( 'The office is closed.' );
}进阶认知:寻找第一个“真值” (Short-circuit evaluation)
当涉及多个非布尔类型的值时,|| 的内部执行算法如下:
- 从左到右依次计算操作数。
- 将当前值转化为布尔值。如果是
true,立即停止计算,并返回这个操作数的初始原始值(不作布尔转换)。 - 如果所有操作数转化后都是
false,则返回最后一个操作数的值。
验证案例:
alert( 1 || 0 ); // 1 (1 已经是真值,立即返回)
alert( null || 1 ); // 1 (null 是假,继续向右找,1 是真值)
alert( undefined || null || 0 ); // 0 (全都是假值,只能返回最后一个)落地用法 1:获取备用默认值
如果某个变量没有值(即假值),我们可以用 || 提供一个默认数据。
let firstName = "";
let nickName = "SuperCoder";
// firstName 假值被跳过,nickName 真值被选中并返回
alert( firstName || nickName || "Anonymous"); // 输出: SuperCoder落地用法 2:短路求值控制执行
利用“遇到真值就停止”的特性,可以控制代码是否执行:
// 因为左侧是 true,运算立即停止,右侧的 alert 不会被执行!
true || alert("not printed");
// 左侧是 false,运算必须向右看,所以触发了 alert 的执行
false || alert("printed");&&(逻辑与 AND)
传统认知: 只有两边都是 true 时才返回 true,只要有一个是 false,结果就是 false。
进阶认知:寻找第一个“假值”
与 || 的逻辑恰好相反,&& 的执行算法是:
- 从左到右计算操作数。
- 将当前值转为布尔值。如果是
false,立即停止计算,并返回这个操作数的初始原始值。 - 如果所有操作数转化后都是
true,则返回最后一个操作数的值。
验证案例:
// 如果第一个是假值,立即返回它,后面的全被忽略(短路)
alert( null && 5 ); // null
alert( 0 && "no matter what" ); // 0
// 如果全都是真值,返回最后一个
alert( 1 && 2 && 3 ); // 3补充说明:优先级问题
与运算&&的优先级高于或运算||。
所以表达式a && b || c && d会被解析为(a && b) || (c && d)。
避坑提示:不要滥用
&&替代if
有时人们利用&&遇到假值就短路的特性来缩写if语句:(x > 0) && alert( 'Greater than zero!' );
虽然代码变短了,但语义不清。强烈建议:控制执行流程请用if,处理逻辑运算请用&&。
!(逻辑非 NOT)
规则: ! 拥有逻辑运算符中最高的优先级。它接收一个参数,将其转为布尔类型后,取反。
alert( !true ); // false
alert( !0 ); // true (0转布尔为false,取反为true)落地用法:双重非 !! 强制转布尔
有时我们使用两个 !! 来将某个值强行转换为布尔类型(效果等同于 Boolean(value))。第一个 ! 负责转换并取反,第二个 ! 再把它反回来。
alert( !!"non-empty string" ); // true模块小结: 逻辑运算符的强大在于“短路效应”。
||寻找第一个真值(常用于赋默认值),&&寻找第一个假值(常用于提前拦截)。理解它们返回的是“原始值”而非“布尔值”,是进阶 JS 的关键一步。
核心任务(练习题)
任务:分析或运算、与运算及短路结果
请写出以下几段代码的输出结果:
alert( null || 2 || undefined );alert( alert(1) || 2 || alert(3) );alert( 1 && null && 2 );alert( alert(1) && alert(2) );alert( null || 2 && 3 || 4 );
解决方案分析:
- 输出
2。||找第一个真值。null是假,遇到2是真,立刻返回2。 - 依次输出
1然后2。- 首先执行左侧的
alert(1),弹出1。 - 注意
alert函数没有显式的return,默认返回undefined。 - 此时表达式变成
undefined || 2 || alert(3)。 - 遇到
2是真值,运算短路停止,最后最外层的alert打印出2。alert(3)不会执行。
- 首先执行左侧的
- 输出
null。&&找第一个假值。1是真,继续向右;遇到null是假值,立即返回null。 - 依次输出
1然后undefined。- 先执行
alert(1)弹出1,返回undefined。 - 此时变成
undefined && alert(2)。 undefined是假值,&&立即停止运算并返回undefined。外层alert打印undefined。
- 先执行
- 输出
3。- 优先级
&&高于||,先算2 && 3。两个都是真值,返回最后一个即3。 - 表达式变为
null || 3 || 4。 ||寻找第一个真值,即3,最终打印3。
- 优先级
任务:区间检查
- 写一个
if条件,检查age是否位于14到90的闭区间(包含界限)。 - 写一个
if条件,检查age是否不在该闭区间。
解决方案:
// 1. 在区间内
if (age >= 14 && age <= 90)
// 2. 不在区间内 (用 NOT 非运算符)
if (!(age >= 14 && age <= 90))
// 2. 不在区间内 (用 OR 或运算符,更好理解)
if (age < 14 || age > 90)任务:登录校验流程编写
使用嵌套的 if 块实现一个复杂的校验逻辑。
- 使用
prompt询问 "Who's there?"。 - 如果输入 "Admin",则继续用
prompt询问密码。- 密码是 "TheMaster",提示 "Welcome!"
- 密码为空或取消,提示 "Canceled"
- 其他密码,提示 "Wrong password"
- 如果用户名为空或取消(
null),提示 "Canceled"。 - 否则提示 "I don't know you"。
解决方案:
let userName = prompt("Who's there?", '');
// 步骤 1:判断用户名
if (userName === 'Admin') {
// 步骤 2:密码环节
let pass = prompt('Password?', '');
if (pass === 'TheMaster') {
alert( 'Welcome!' );
} else if (pass === '' || pass === null) {
alert( 'Canceled' );
} else {
alert( 'Wrong password' );
}
} else if (userName === '' || userName === null) {
alert( 'Canceled' );
} else {
alert( "I don't know you" );
}注:注意嵌套
if结构中的层级缩进,这能极大提高代码的可读性。
【本篇核心逻辑复盘】
- 关于类型: 牢记
null和undefined在不同场景(算术运算 vs 相等比较)下截然不同的表现。防范"0"变true的布尔陷阱。 - 关于运算:
+既是数学加法,又是字符串拼接器,同时还是一元强制转数字神器。清楚算术运算符隐式转数字的铁律。 - 关于比较:
===才是你永远的忠实护卫,在无法确定数据类型时,拒绝使用==。 - 关于分支:
if控制流程走向,?三元运算符负责基于条件返回值。两者职责分明,切勿越界混用。 - 关于逻辑:
||找真,&&找假。它们返回的是引发停机的那个“原始值”,利用这一短路求值特性,我们能写出更加精简强悍的默认值赋值和防御性代码。
