Skip to content

作业题目分析与题目分析(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,循环用循环语句。
易错点:表达式可以组成更复杂语句,但语句不一定能当值用;分号或换行是语句结束符,概念上先有印象,写多了自然清楚。

课堂画面 ​

课堂画面 1

课堂画面 2

课堂画面 3

课堂画面 4

课堂画面 5

课堂画面 6

代码示例 ​

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。
  • 不确定优先级时直接加小括号,小括号内的内容永远先算,这是最稳妥的写法。

常见错误 ​

  1. 现象:把 parseInt/parseFloat 当 Number() 用,parseInt("12px") 得到 12 就以为类型转换都这样。
    原因:混淆“严格转换”和“提取数字前缀”。
    修法:严格转换优先 Number();确实要解析前缀时再用 parseInt/parseFloat,并明确进制参数。

  2. 现象:认为 100 && 200 的结果一定是 true/false。
    原因:忽略逻辑与/或返回的是操作数,不一定是布尔值。
    修法:先判断短路路径,再看返回值;需要布尔值时显式写 Boolean(...) 或比较表达式。

  3. 现象:let n=1; n++ || n++; 以为右侧一定执行,最终 n 算错。
    原因:没有先判断逻辑或的短路条件。
    修法:含副作用的表达式分步写,先判断左侧是否已成立,再决定右侧是否执行。

  4. 现象:let a=1; let b=a++ + ++a; 中 a、b 取值混淆。
    原因:没有区分“表达式取值时点”和“变量更新时点”。
    修法:拆成多行,用临时变量记录每一步的值;不要在一行堆多个自增自减。

  5. 现象:用 == 判断 null、undefined、空串、0,结果与直觉不符。
    原因:相等比较存在特殊规则,且隐式转换干扰判断。
    修法:默认使用 ===;特殊值判空写成显式条件,如 x === null || x === undefined。

  6. 现象:复杂表达式中凭感觉判断优先级,运行结果与手算不一致。
    原因:优先级和结合性记混,尤其是逻辑、赋值、三元、逗号。
    修法:不确定就加括号;先拆成多条语句,再逐步合并。

练习 ​

  1. 手算并写出 n 的最终值:
    let n = 5; let r = n++ > 5 && ++n > 6; console.log(r, n);

  2. 手算并写出 a、b 的值:
    let a = 1; let b = a++ + ++a; console.log(a, b);

  3. 写出下列输出结果:
    console.log(parseInt("08"), Number("08"), Number(""), Boolean(" "));

  4. 给表达式 100 > 20 && 30 || 0 加上显式括号,并写出最终结果。

  5. 将下面代码改成三元表达式:
    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

小结 ​

  1. 类型转换题先分清“严格转换”和“前缀解析”,不要混用函数。
  2. 含自增自减、赋值的题必须分步演算,分别记录“取值”和“变量更新”。
  3. 逻辑与/或先看短路,再谈返回值;不要默认结果一定是布尔值。
  4. 判等优先用 ===,特殊值单独设计测试用例验证。
  5. 复杂表达式先加括号或拆语句,优先级不要靠死记硬背。
  6. 三元表达式适合简单二选一;分支里有副作用或逻辑复杂时用 if/else。
  7. 练习要形成“手算→运行验证→记录错因”的闭环,重点复盘短路和副作用。