流程控制、数组与集合 这一篇讲 JS 的流程控制 (if / switch / 异常)、循环 (for / while / for…in / for…of)、数组 、Set 与 Map ,以及各类遍历方式 。
其中 for...in、for...of、数组的高阶方法(map/filter/reduce)是 JS 与 Java 差异最大的部分;if、for、switch 等基础语法与 Java 几乎一致,只做对照。
阅读方式:与 Java 相同的语法简单带过,重点看「差异」和「⚠️ 坑点」。
一、流程控制 1. if / else if / else(与 Java 相同) 1 2 3 4 5 6 7 if (a > 0 ) { } else if (a === 0 ) { } else { }
唯一差异:条件表达式不强制是 boolean ,JS 会用 truthy/falsy 自动判断(0、""、null、undefined、NaN 都走 else,见第 1 篇)。
2. switch(基本与 Java 相同) 1 2 3 4 5 6 7 8 9 10 11 switch (x) { case 1 : break ; case 2 : case 3 : break ; default : }
JS 的 switch 用 === 严格相等 比较(不隐式转换)。
与 Java 一样有 fall-through :漏写 break 会继续执行下一个 case。
case 后面可以是表达式 ,不限于常量。
3. 三元运算符(同 Java) 1 let y = x > 0 ? "正" : "非正" ;
4. break / continue(同 Java) break 跳出循环、continue 跳过本次,for...in/for...of 里同样适用。
5. 异常处理 try / catch / finally 1 2 3 4 5 6 7 try { } catch (err) { console .log (err.message ); } finally { }
与 Java 的差异:
catch 不声明异常类型 (Java 要写 catch (ExceptionType e))。
throw 可以抛任意值 (字符串、数字、对象都行),但推荐抛 Error:
二、循环 1. for / while / do-while(与 Java 相同,带过) 1 2 3 for (let i = 0 ; i < arr.length ; i++) { }while (cond) { }do { } while (cond);
注意:循环计数器用 let,不要用 var(var 无块级作用域,闭包场景会出经典 bug)。
2. for…of(遍历”值”,重点) 对应 Java 的增强 for-each(for (int x : arr)),遍历可迭代对象的值 :
1 2 3 4 for (const item of [1 , 2 , 3 ]) { }for (const ch of "hello" ) { }for (const v of set) { }for (const [k, v] of map) { }
小细节:循环变量可以写 const item,每次迭代都是独立作用域,放心用 const。
3. for…in(遍历”键/索引”,重点) 遍历对象的可枚举属性名 (字符串):
1 2 3 4 5 6 7 8 9 const obj = { a : 1 , b : 2 };for (const key in obj) { console .log (key); console .log (obj[key]); } for (const index in [10 , 20 ]) { console .log (index); }
⚠️ 坑点 :
for...in 遍历数组得到的是字符串索引 ,还会带上原型上的可枚举属性,所以数组不要用 for…in ,用 for...of 或 forEach。
遍历对象时,为避免原型链上的继承属性,常配合 hasOwnProperty 判断(或直接用 Object.keys)。
4. for…of 与 for…in 对比(核心)
for...of
for...in
遍历内容
值
键名 / 索引
适用对象
数组、字符串、Set、Map 等可迭代对象
普通对象、数组
数组
遍历元素值
遍历索引(字符串)
普通对象
❌ 不能直接用(对象不可迭代,会报错)
✅ 遍历属性名
1 2 3 4 let arr = ["a" , "b" , "c" ];for (let v of arr) console .log (v); for (let k in arr) console .log (k);
记忆口诀:**of 取”值”,in 取”键”**。
5. 遍历普通对象(补充) 1 2 3 4 5 Object .keys (obj); Object .values (obj); Object .entries (obj); for (const [key, value] of Object .entries (obj)) { }
三、数组 Array JS 数组是动态长度 、可存混合类型 ,兼具 Java 的”数组”和 ArrayList 的特点。
1. 创建与访问 1 2 3 4 let arr = [1 , 2 , 3 ]; let arr2 = new Array (3 ); arr[0 ]; arr.length ;
2. 增删元素 1 2 3 4 5 arr.push (4 ); arr.pop (); arr.unshift (0 ); arr.shift (); arr.splice (1 , 2 , 'a' );
方法
位置
作用
push / pop
尾部
加 / 删(类比栈)
unshift / shift
头部
加 / 删
splice(start, n, ...)
任意
删除 + 插入
3. 查找 1 2 3 4 arr.indexOf (2 ); arr.includes (2 ); arr.find (x => x > 2 ); arr.findIndex (x => x > 2 );
4. 遍历与高阶方法(重点,对应 Java Stream) 1 2 3 4 5 6 7 arr.forEach ((item, index ) => { }); arr.map (x => x * 2 ); arr.filter (x => x > 1 ); arr.reduce ((acc, x ) => acc + x, 0 ); arr.some (x => x > 1 ); arr.every (x => x > 0 );
JS 方法
作用
Java 对应
map
映射变换
Stream.map
filter
过滤
Stream.filter
reduce
归并累加
Stream.reduce
forEach
遍历
forEach
some / every
存在性 / 全量判断
anyMatch / allMatch
find / findIndex
查找
findFirst
⚠️ 这些方法不修改原数组 (map/filter 返回新数组,forEach 返回 undefined)。reduce 回调是 (累计值, 当前值),和 Java 的 reduce(初始值, 累加器) 参数顺序相反,注意区分。
5. 排序与转换 1 2 3 4 5 6 arr.sort ((a, b ) => a - b); arr.reverse (); arr.join ('-' ); arr.slice (1 , 3 ); arr.concat (arr2); arr.flat ();
⚠️ sort 的坑 :默认按字符串 排序,数字会排错:
1 2 [3 , 1 , 10 , 2 ].sort (); [3 , 1 , 10 , 2 ].sort ((a, b ) => a - b);
6. 解构与展开 1 2 let [a, b] = [1 , 2 ]; let arr3 = [...arr, 4 ];
四、Set 与 Map 1. Set(集合,对应 Java HashSet) 元素唯一、自动去重 :
1 2 3 4 5 6 7 8 let s = new Set ([1 , 2 , 2 , 3 ]); s.add (4 ); s.delete (2 ); s.has (3 ); s.size ; s.clear (); for (const v of s) { }
去重是 Set 最常用场景:
1 let unique = [...new Set (arr)];
2. Map(键值对,对应 Java HashMap) 1 2 3 4 5 6 7 8 9 10 11 let m = new Map ();m.set ("name" , "Tom" ); m.set (1 , "one" ); m.get ("name" ); m.has ("name" ); m.delete ("name" ); m.size ; m.clear (); for (const [k, v] of m) { }m.forEach ((v, k ) => { });
⚠️ 与 Java 的差异:
Map 的键可以是任意类型 (含原始类型、对象),不像 Java 键必须是引用类型。
m.size 是属性 ,Java 的 map.size() 是方法。
forEach 回调参数顺序是 (值, 键),和直觉相反,容易搞混。
3. 普通对象 vs Map(怎么选)
普通对象 {}
Map
键类型
只能是字符串 / Symbol
任意类型
大小
无 size,要 Object.keys().length
有 size
遍历
for...in / Object.keys
直接 for...of
插入顺序
不保证(数字键会重排)
保证插入顺序
记忆点:需要”字符串键 + 字面量简洁”用普通对象;需要”任意类型键、频繁增删、保持顺序、有 size”用 Map。
五、速查表
需求
写法
条件分支
if / else if / else
多分支
switch (x) { case ... }
异常捕获
try {} catch (err) {} finally {}
抛出异常
throw new Error("msg")
计数循环
for (let i = 0; i < n; i++)
遍历值
for (const v of arr)
遍历键
for (const k in obj)
遍历对象键值
for (const [k, v] of Object.entries(obj))
尾部加/删
push / pop
头部加/删
unshift / shift
任意删改
splice(start, n, ...)
是否存在
includes
查找索引
indexOf / findIndex
映射
map(x => ...)
过滤
filter(x => ...)
归并
reduce((acc, x) => ..., 0)
数字升序
sort((a, b) => a - b)
数组去重
[...new Set(arr)]
Set 增删查
add / delete / has / size
Map 增删查
set / get / delete / has / size
六、复习要点
if/for/while/switch 与 Java 基本相同;差异在 switch 用 ===、catch 不声明类型、throw 可抛任意值。
**for…of 取”值”(数组/字符串/Set/Map), for…in 取”键”**(对象属性名、数组索引)。
数组是动态的,混合类型;splice 是增删改一体的万能方法。
高阶方法 map/filter/reduce/some/every/find 对应 Java Stream,不修改原数组 。
reduce 回调是 (累计值, 当前值),与 Java 的 (初始值, 累加器) 顺序相反。
sort 默认按字符串排序,数字排序必须传 (a, b) => a - b。
Set 用于去重([...new Set(arr)]),size 是属性不是方法。
Map 键可以是任意类型,forEach 参数顺序是 (值, 键)。
需要”任意键 / 有 size / 保序”用 Map,否则普通对象即可。
忘了某条,回本文对应小节看示例即可。
下一篇预告:函数 ——函数是一等公民、箭头函数、闭包、this 绑定、回调与高阶函数(JS 与 Java 差异最大的部分)。