主题
作业题目分析与题目分析(Day3 1/3)
本页对应 Day03_JavaScript,共 7 段视频,约 1 小时 13 分。
学习目标
- 能准确判断常见数据类型在显式转换与隐式转换中的结果,包括 Number、String、Boolean 转换及 parseInt/parseFloat 的特殊规则。
- 能独立分析包含算术、关系、逻辑、赋值、逗号、typeof、字符串连接等运算符的表达式,正确写出表达式值、变量最终值及是否发生短路。
- 能使用三元运算符编写条件取值表达式,并根据第一个操作数的布尔转换结果准确判断最终取值。
- 能依据运算符优先级、结合性和小括号规则,分步计算复杂表达式并说明每一步的执行顺序与结果。
- 能区分表达式与语句,说明顺序结构、分支结构、循环结构的作用,并能编写基本的 if/else 分支语句。
知识点
一、数据类型转换:先记规则,再分显式与隐式
为什么需要:后面做运算、判断、输出时,类型不一致就会触发转换;不记规则就无法推导表达式结果。怎么想:先分“显式转换”和“隐式转换”。显式是代码不运行也能看出怎么转,如 Number()、String()、Boolean();隐式要看运算符和运算环境。parseInt()、parseFloat() 也能转数字,但主要是从字符串中提取数字部分,规则与 Number() 不同。怎么做:转 Number 时,纯数字字符串转对应数字,空串转 0,两端空格会先去掉,0xAB 这类十六进制表示也会按数字处理;true 转 1,false 转 0,null 转 0,undefined 转 NaN。转 Boolean 时,0、NaN、空串、null、undefined、false 转 false,其余转 true。易错点:字符串转 Boolean 不会去两端空格;parseInt/parseFloat 不等于通用转换规则;转换规则无论显式隐式都要熟记。
二、运算符与表达式:先判断“它是什么运算符”
为什么需要:同一个符号可能有多重身份,如 + 可以是正号、相加、字符串连接。怎么想:先按操作数个数分一元、二元、三元;再按功能分算术、关系比较、逻辑、赋值、其他。表达式最核心的特点是“一定有值”,这个值就是计算结果;变量、直接量也可算简单表达式,多个简单表达式可组成复杂表达式。怎么做:看到表达式先找运算符,再判断操作数类型和副作用。易错点:没有值的不叫表达式;函数参数里的逗号是分隔符,不是逗号运算符。
三、算术与自增自减:副作用决定操作数必须是变量
为什么需要:算术运算最常用,++/-- 又会改变变量本身。怎么想:+ - * / % 是二元运算符,要求操作数转 Number,结果也是 Number,且没有副作用;正负号是一元运算符,结果取操作数转 Number 后的值。++/-- 有副作用,会改变操作数,所以操作数必须是变量。怎么做:前置 ++n 先加再取值;后置 n++ 先取值再加。易错点:普通算术转换不改变原变量;++/-- 写直接量没有意义。
js
let n = 100;
console.log(n++ && n--); // 101,n 最终为 100
console.log(--n || n++); // 99,n 最终为 99推导:n++ 取 100,n 变 101;n-- 取 101,n 变 100;逻辑与第一项真,取第二项,结果 101。接着 --n 取 99,n 变 99;逻辑或第一项真,短路,不执行后面的 n++,结果 99。
四、关系比较:大小、相等与全等
为什么需要:条件判断离不开比较。怎么想:比大小一般转 Number;但两个操作数都是字符串时,按字符串规则逐字符比较 Unicode。== 类型不同通常转 Number 再比;类型相同再判断值。=== 要求类型一致且值相同。怎么做:优先用 ===,需要自动转换时再考虑 ==。易错点:null 特殊,null == 0、null == ''、null == false 都不成立,但 null == undefined 成立;NaN 不等于自身;字符串 "ABC" < "B" 成立,因为逐字符比较。
五、逻辑运算:短路与返回值
为什么需要:组合条件、控制执行。怎么想:&&、|| 会把操作数转布尔判断,但表达式返回值不一定布尔,而是从操作数中取一个;! 返回布尔。怎么做:&& 第一项假就返回第一项,否则返回第二项;|| 第一项真就返回第一项,否则返回第二项。易错点:短路后第二项可能根本不执行;操作数本身不会被改成布尔。
js
console.log(100 > 20 && 1000); // 1000
console.log(false || "默认值"); // "默认值"六、赋值、其他运算符与三元
为什么需要:赋值有副作用,三元可做条件取值。怎么想:赋值左边必须是变量,右边无所谓;复合赋值如 += 还带类型要求。typeof 返回类型字符串;逗号运算符取最后一个表达式的值;+ 只要有一个操作数是字符串就是连接。三元运算符 条件 ? 值1 : 值2:第一项转布尔,真取第二项,假取第三项,无副作用。怎么做:
js
let res1 = true ? 100 : 200; // 100
let res2 = false ? 100 : 200; // 200
let age = 19;
let msg = age >= 18 ? "成年人" : "未成年人";易错点:+ 先看操作数个数和类型;三元只执行被选中的分支。
七、优先级与连续赋值
为什么需要:复杂表达式要先算谁后算谁。怎么想:一元最高,其次算术,再关系,再逻辑与、逻辑或,再三元,再赋值,逗号最低;括号最高。赋值连续时从右往左。怎么做:不确定就加括号。易错点:逻辑与优先级高于逻辑或;赋值最后算;逗号最低。
js
let a, b, c;
a = b = c = 100; // 从右往左,三者都是 100八、语句与流程控制
为什么需要:程序默认顺序执行,但要做判断和重复。怎么想:语句不一定有值,表达式有值;a = 100 可作表达式语句,但 var b = 250 不能直接拿去输出。流程控制三大结构:顺序、分支、循环。怎么做:分支用 if/else,循环后续学。易错点:别把“语句”都当表达式;默认顺序结构,写了就会按顺序执行。
本节回顾:先把知识地图摆出来
1. 数据类型转换
1.1 数据类型转换规则
① 转为number
string: 纯数字字符串、空字符串
boolean: true->1 false->0
null: 0
undefined: NaN
② 转为 stirng
③ 转为 boolean
false: 0、NaN、空字符、null、undefined
1.2 强制类型转换
Number() parseInt() parseFloat()
String()
Boolean()
1.3 自动类型转换
根据所在的运算环境自动类型转换
2. 运算符
2.1 算术
+ - * / % + - ++ --
2.2 关系
> < >= <=
== != === !==
2.3 逻辑
&& || !
2.4 赋值
= += -= *= /= %= +=
2.5 其他运算符
typeof , +这张图不是让你背名词,而是让你遇到表达式时能按顺序问:这里会不会转换?谁转谁?运算符要不要副作用?优先级先算谁? 下面按“为什么需要→怎么想→怎么做→易错点”回顾。
数据类型转换规则:先记“转成什么”,再谈怎么转
为什么需要:JS是弱类型语言,运算时经常发生类型转换;不记规则,表达式结果就只能靠猜。
怎么想:先看目标类型。转number时,纯数字字符串变对应数字,空字符串变0,字符串两端空格会先自动去掉;十六进制形式如0xAB也会按数字识别。true变1,false变0;null变0;undefined变NaN。转string基本就是“长得什么样,字符串内容就是什么”。转boolean只需记住false的情况:0、NaN、空字符串、null、undefined,其余基本都是true。
怎么做:遇到混合类型先标出目标类型,再套规则。比如Number('')是0,Number(undefined)是NaN。
易错点:只有转number会去两端空格,转boolean不会;parseInt/parseFloat主要是提取字符串中的数字部分,规则和Number()不完全一样,不能混着背。
强制转换与自动转换:显式靠函数,隐式看环境
为什么需要:有时要主动控制类型,有时类型转换是运算符“顺手”做的。
怎么想:强制转换也叫显式转换,代码不运行你就能知道怎么转;自动转换也叫隐式转换,要看运算符和运算环境。
怎么做:显式用Number()、String()、Boolean(),以及parseInt()、parseFloat()。隐式则看表达式,比如算术运算通常要求number,不是number就转number。
易错点:隐式转换不是“把原变量改了”,多数只是把转换后的值拿去运算;原变量本身通常不变。只有++/--、赋值这类有副作用的运算符才会改变变量。
算术运算符:类型转换不等于副作用
为什么需要:+ - * / %和++ --长得像,但行为差别很大。
怎么想:二元算术+ - * / %要求操作数是number,不是就自动转,表达式结果也是number,并且没有副作用。正负号是一元运算符,也要求number,结果就是取正或取反。++/--有副作用,会改变操作数。
怎么做:++/--的操作数必须是变量;前缀先增减再取表达式的值,后缀先取增减前的值再增减。
易错点:前面几个运算符虽然发生类型转换,但不叫副作用;100++这种写法不成立,因为直接量不能自己改自己。
关系与相等:两个字符串比大小,null是特殊情况
为什么需要:条件判断离不开比较,==和===混用很容易出错。
怎么想:比大小一般转number再比;但如果两个操作数都是string,就按字符串规则逐字符比较,用Unicode编码,一个字符大就可能决定整个字符串大。判等==在类型不一致时通常转number再比;类型一致就直接比。===要求类型一致,类型不同直接false。
怎么做:转写稿里的调试很典型:'ABC' < 'B'为true,因为逐字符比;null == 0、null == ''、null == false都不成立,但null == undefined成立;100 === '100'直接false。
易错点:null的相等判断是特殊情况,不要硬套“都转number”;实际开发优先用===,需要自动转换时再考虑==。
逻辑运算:短路决定“取哪个操作数”
为什么需要:逻辑运算不仅做真假判断,还常用来写短路逻辑。
怎么想:&&和||会把操作数转boolean来判断,但表达式结果不一定boolean,而是从两个操作数中取一个。&&:第一个成立就取第二个,不成立就取第一个,且第二个不看;||:第一个成立就取第一个,不成立才取第二个。!是一元,把操作数转boolean后取反。
怎么做:转写稿案例100 > 20 && 1000,左边true,所以取1000;100 || 20 && 40结果为100,说明&&优先级高于||,先算20 && 40得40,再算100 || 40取100。
易错点:短路会跳过后面代码,若后面有n++等副作用,不执行就不会改变变量。
赋值、逗号、typeof与加号:别把分隔符当运算符
为什么需要:这些运算符常混在表达式里,尤其逗号和加号容易误判。
怎么想:赋值有副作用,只针对左边,所以左边必须是变量,右边可以是变量、直接量、表达式;连续赋值A = B = C = 100从右往左算。逗号是二元运算符,取最后一个表达式的值,优先级最低;但函数括号里的逗号是参数分隔符,不是运算符。typeof是一元运算符,结果是字符串。+有三个作用:正号、相加、字符串连接;两个操作数只要有一个是string,就是字符串连接。
怎么做:40 + 4 > 48 && 67 + --A,先算一元--A,再算加法和比较,最后&&。
易错点:看见字符串不一定就是连接,要先看操作数个数;+ 'hello'是一元正号,会尝试转number,得到NaN。
优先级与三元:小括号最稳,条件成立取第二个
为什么需要:复杂表达式必须先确定计算顺序;三元运算符可做简单条件判断。
怎么想:大体顺序是一元最高,其次算术,再关系,再逻辑(&&高于||),再三元,再赋值,逗号最低;小括号可提高优先级。三元运算符是唯一三元运算符,第一个操作数转boolean判断,成立取第二个,不成立取第三个;后两个无类型要求,且只执行被选中的分支。
怎么做:true ? 100 : 200得100;67 % 4 ? 10 : 10 * 4中67%4为3,成立,取10。转写稿案例n=10; n++ ? n++ : n++:条件取10成立,n变11;取第二个n++得11,n变12;第三个不执行,所以结果11,n为12。
易错点:三元不是“两个运算符”,而是? :整体;不要忽略短路,没被选中的分支不会执行。
语句与流程控制:表达式有值,语句不一定
为什么需要:后面要学分支和循环,先分清表达式和语句。
怎么想:表达式一定有值;语句是指令,不一定有值。A = 100既是赋值表达式,也可作为表达式语句;但前面加var后更强调语句身份。默认程序按书写顺序执行,叫顺序结构;分支结构用条件决定执行哪段;循环结构让语句重复执行。
怎么做:不要试图把纯语句塞进console.log输出;后续分支用if/else,循环用循环语句。
易错点:表达式可以组成更复杂语句,但语句不一定能当值用;分号或换行是语句结束符,概念上先有印象,写多了自然清楚。
课堂画面






代码示例
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Day03 数据类型转换与运算符回顾</title>
</head>
<body>
<script>
// 一、其他类型转 number
console.log(Number('100')); // 100 纯数字字符串
console.log(Number('')); // 0 空字符串
console.log(Number(' 100 ')); // 100 转 number 前会去掉两端空格
console.log(Number('0xAB')); // 171 十六进制字符串也按数字处理
console.log(Number(true)); // 1
console.log(Number(false)); // 0
console.log(Number(null)); // 0
console.log(Number(undefined)); // NaN
// parseInt / parseFloat 主要用于提取字符串中的数字部分
console.log(parseInt('100px')); // 100
console.log(parseFloat('3.14abc')); // 3.14
// 二、其他类型转 boolean:只有这 5 种情况是 false
console.log(Boolean(0)); // false
console.log(Boolean(NaN)); // false
console.log(Boolean('')); // false
console.log(Boolean(null)); // false
console.log(Boolean(undefined)); // false
console.log(Boolean(' ')); // true 转 boolean 不会去掉空格
console.log(Boolean([])); // true 除了上面 5 种,其余都是 true
// 三、相等与全等
console.log(1 == '1'); // true 类型不同,转 number 再比
console.log(1 === '1'); // false 全等要求类型也一致
console.log(null == 0); // false null 的特殊情况
console.log(null == ''); // false
console.log(null == false); // false
console.log(null == undefined); // true
// 四、两个字符串比大小:按 unicode 逐字符比较
console.log('ABC' < 'B'); // true 'A' 的编码小于 'B'
// 五、逻辑与 / 逻辑或:表达式的值取自两个操作数之一
console.log(100 && 200); // 200 第一个成立,取第二个
console.log(0 && 200); // 0 第一个不成立,直接取第一个
console.log(100 || 200); // 100 第一个成立,取第一个,第二个不执行
console.log(0 || 200); // 200 第一个不成立,取第二个
console.log(!100); // false
</script>
</body>
</html>要点解释:
- 转 number 时只有“纯数字字符串”和“空字符串”能成功,其余转不动的都是
NaN;转之前会自动去掉两端空格,这条只对转 number 生效。 parseInt/parseFloat的规则与Number()不同,它们是从字符串中“抠”出数字部分,parseInt('100px')能得 100。- 转 boolean 只记 5 个 false:
0、NaN、''、null、undefined,其余全是 true。易错点:Boolean(' ')是 true,因为转布尔不去空格。 null的判等是特殊情况:null == 0、null == ''、null == false全部为 false,只有null == undefined为 true,不要用常规转换规则去推。==会做类型转换,===先看类型,类型不一致直接 false,所以实际开发优先用===。- 逻辑与/逻辑或的值不一定是布尔,而是从两个操作数中取一个:
&&第一个成立取第二个,||第一个成立取第一个,且第二个操作数不会执行。
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Day03 自增自减与三元运算符</title>
</head>
<body>
<script>
// 一、自增自减:运算符在前先自增再取值,在后先取值再自增
let n = 100;
console.log(n++ && n--); // 101
console.log(n); // 100
console.log(--n || n++); // 99
console.log(n); // 99 n++ 没有执行
// 二、三元运算符:第一个操作数成立取第二个,不成立取第三个
let res1 = true ? 100 : 200;
let res2 = false ? 100 : 200;
console.log(res1, res2); // 100 200
// 第一个操作数可以是任意表达式,会先转成布尔再判断
let res3 = 67 % 4 ? 10 * 5 : 10 * 4;
console.log(res3); // 50 67 % 4 = 3,成立
// 三、三元运算符 + 自增:没有被选中的分支不会执行
let m = 10;
let res4 = m++ ? m++ : m++;
console.log(res4, m); // 11 12
// 四、实际用途:条件判断
let age = 19;
let msg = age >= 18 ? '成年人' : '未成年人';
console.log('恭喜你,你是一个' + msg + ',欢迎光临');
</script>
</body>
</html>要点解释:
n++取值是自增前的值,但变量本身已经加 1;++n是先加 1 再取值。表达式取值和变量变化要分开算。n++ && n--:第一个操作数取 100(成立),n 变 101;第二个n--取 101,n 回到 100;表达式结果是 101。--n || n++:--n先减再取,n 从 100 变 99,结果 99 成立,||直接取第一个值,后面的n++根本不会执行,所以 n 最终是 99。易错点:短路导致后面的自增没有发生。- 三元运算符是唯一的三元运算符,第一个操作数不是布尔会先转布尔,但只影响判断,不改变操作数本身。
m++ ? m++ : m++:第一个m++取 10(成立),m 变 11;执行第二个m++取 11,m 变 12;第三个分支不执行,所以res4是 11、m 是 12。- 三元运算符本身没有副作用,常用于简化 if...else 的条件判断。
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Day03 运算符优先级</title>
</head>
<body>
<script>
// 一、算术 > 关系 > 逻辑 > 赋值
console.log(10 + 7 * 2); // 24 先乘后加
console.log((10 + 7) * 2); // 34 小括号优先级最高
console.log(100 > 45 + 4 * 2); // true 先算 45 + 8 = 53
console.log(100 > 20 && 1000); // 1000 先算 100 > 20,成立取第二个
// 二、逻辑与优先级高于逻辑或
console.log(100 || 20 && 40); // 100 先算 20 && 40 得 40,再 100 || 40
// 三、一元运算符优先级最高
console.log(100 + !20); // 100 先 !20 得 false,false 转 0
// 四、比大小高于判等
console.log(1 == 50 > 20); // true 先算 50 > 20 得 true,1 == true
// 五、赋值运算符最后算,连续赋值从右往左
let a, b, c;
a = b = c = 100;
console.log(a, b, c); // 100 100 100
// 六、综合表达式
let A = 10;
let res = 45 + 4 > 48 && 67 + --A;
console.log(res); // 76 49 > 48 成立,取 67 + 9
</script>
</body>
</html>要点解释:
- 优先级从高到低记:一元运算符(
++、--、!、+、-、typeof)> 算术(乘除取余高于加减)> 关系(比大小高于判等)> 逻辑(&&高于||)> 三元 > 赋值 > 逗号。 100 || 20 && 40的结果是 100 而不是 40,因为&&优先级高于||,先把20 && 40算成 40,再100 || 40取 100。易错点:不要把||和&&当成同级从左往右。100 + !20先算!20得 false,false 参与加法自动转 0,结果是 100。1 == 50 > 20先算>得 true,再1 == true成立。比大小优先级高于判等。- 连续赋值
a = b = c = 100从右往左:先算c = 100,整个表达式的值就是 100,再赋给 b、a,所以三个变量都是 100。 - 综合表达式先算一元
--A(A 变 9),再算加法45 + 4、67 + 9,再算>,最后算&&;49 > 48成立,取第二个操作数 76。 - 不确定优先级时直接加小括号,小括号内的内容永远先算,这是最稳妥的写法。
常见错误
现象:把
parseInt/parseFloat当Number()用,parseInt("12px")得到12就以为类型转换都这样。
原因:混淆“严格转换”和“提取数字前缀”。
修法:严格转换优先Number();确实要解析前缀时再用parseInt/parseFloat,并明确进制参数。现象:认为
100 && 200的结果一定是true/false。
原因:忽略逻辑与/或返回的是操作数,不一定是布尔值。
修法:先判断短路路径,再看返回值;需要布尔值时显式写Boolean(...)或比较表达式。现象:
let n=1; n++ || n++;以为右侧一定执行,最终n算错。
原因:没有先判断逻辑或的短路条件。
修法:含副作用的表达式分步写,先判断左侧是否已成立,再决定右侧是否执行。现象:
let a=1; let b=a++ + ++a;中a、b取值混淆。
原因:没有区分“表达式取值时点”和“变量更新时点”。
修法:拆成多行,用临时变量记录每一步的值;不要在一行堆多个自增自减。现象:用
==判断null、undefined、空串、0,结果与直觉不符。
原因:相等比较存在特殊规则,且隐式转换干扰判断。
修法:默认使用===;特殊值判空写成显式条件,如x === null || x === undefined。现象:复杂表达式中凭感觉判断优先级,运行结果与手算不一致。
原因:优先级和结合性记混,尤其是逻辑、赋值、三元、逗号。
修法:不确定就加括号;先拆成多条语句,再逐步合并。
练习
手算并写出
n的最终值:let n = 5; let r = n++ > 5 && ++n > 6; console.log(r, n);手算并写出
a、b的值:let a = 1; let b = a++ + ++a; console.log(a, b);写出下列输出结果:
console.log(parseInt("08"), Number("08"), Number(""), Boolean(" "));给表达式
100 > 20 && 30 || 0加上显式括号,并写出最终结果。将下面代码改成三元表达式:
let msg; if (age >= 18) { msg = "成年人"; } else { msg = "未成年人"; }
原视频对照
| # | 视频 | 时长 |
|---|---|---|
| 1 | 回顾 | 20:31 |
| 2 | 作业题目分析 | 02:38 |
| 3 | 题目分析 | 10:52 |
| 4 | 题目分析 | 02:16 |
| 5 | 三元运算符 | 11:17 |
| 6 | 运算符的优先级 | 21:09 |
| 7 | 语句和流程控制结构 | 04:44 |
小结
- 类型转换题先分清“严格转换”和“前缀解析”,不要混用函数。
- 含自增自减、赋值的题必须分步演算,分别记录“取值”和“变量更新”。
- 逻辑与/或先看短路,再谈返回值;不要默认结果一定是布尔值。
- 判等优先用
===,特殊值单独设计测试用例验证。 - 复杂表达式先加括号或拆语句,优先级不要靠死记硬背。
- 三元表达式适合简单二选一;分支里有副作用或逻辑复杂时用
if/else。 - 练习要形成“手算→运行验证→记录错因”的闭环,重点复盘短路和副作用。