循环语句规范
循环语句是JavaScript中控制流程的重要工具,合理的规范能提升代码可读性和维护性。以下是常见的循环语句规范及实践建议。
基本循环类型的选择
优先使用for
循环处理已知迭代次数的场景,while
循环适合条件不确定的情况,for...of
用于可迭代对象遍历。避免使用for...in
遍历数组,除非需要处理稀疏数组的特殊情况。
// 推荐 - 数组遍历
const arr = [1, 2, 3];
for (let i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
// 推荐 - 可迭代对象
const set = new Set([1, 2, 3]);
for (const item of set) {
console.log(item);
}
循环控制变量
循环计数器应使用let
声明,避免污染外部作用域。计数器命名应具有描述性,单字母变量仅限简单循环。
// 不推荐
for (var i = 0; i < 10; i++) { /*...*/ }
// 推荐
for (let index = 0; index < users.length; index++) {
const user = users[index];
// ...
}
循环体复杂度控制
单个循环体内代码不应超过20行,复杂逻辑应提取为独立函数。嵌套循环超过两层时应考虑重构。
// 不推荐
for (const item of list) {
// 50行业务逻辑...
}
// 推荐
function processItem(item) {
// 复杂逻辑封装
}
for (const item of list) {
processItem(item);
}
提前终止与跳过
合理使用break
和continue
时需添加注释说明条件。return
可用于终止整个包含循环的函数。
for (const user of users) {
if (user.inactive) continue; // 跳过非活跃用户
if (user.role === 'admin') {
foundAdmin = user;
break; // 找到第一个管理员即终止
}
}
性能优化要点
缓存数组长度、避免循环内重复计算、减少DOM操作等性能关键点需特别注意。
// 优化前
for (let i = 0; i < document.getElementsByTagName('div').length; i++) {
// 每次循环都重新计算长度
}
// 优化后
const divs = document.getElementsByTagName('div');
for (let i = 0, len = divs.length; i < len; i++) {
// 缓存长度
}
异步循环处理
使用for...of
配合await
处理异步循环,避免forEach
中的异步问题。
// 不推荐
items.forEach(async (item) => {
await process(item); // 不会按预期等待
});
// 推荐
for (const item of items) {
await process(item); // 顺序执行
}
不可变原则
在循环中修改正在遍历的数组可能导致意外行为,需要特殊处理时应先创建副本。
const numbers = [1, 2, 3, 4];
// 危险操作
for (let i = 0; i < numbers.length; i++) {
if (numbers[i] % 2 === 0) {
numbers.splice(i, 1); // 改变原数组
i--; // 必须手动调整索引
}
}
// 更安全的方式
const filtered = numbers.filter(n => n % 2 !== 0);
循环与函数式编程
现代JavaScript中,许多循环场景可用map
/filter
/reduce
等函数式方法替代,但需注意性能差异。
// 传统循环
let sum = 0;
for (const num of numbers) {
sum += num;
}
// 函数式方案
const sum = numbers.reduce((acc, num) => acc + num, 0);
错误处理模式
循环内部的错误处理应使用try-catch
包裹具体操作,避免因单个失败中断整个循环。
for (const task of tasks) {
try {
await executeTask(task);
} catch (error) {
console.error(`Task ${task.id} failed:`, error);
continue; // 继续后续任务
}
}
循环变量作用域
使用let
声明的循环变量具有块级作用域,var
会导致变量提升和共享问题。
// 问题示例
var funcs = [];
for (var i = 0; i < 3; i++) {
funcs.push(() => console.log(i)); // 全部输出3
}
// 正确方案
const funcs = [];
for (let i = 0; i < 3; i++) {
funcs.push(() => console.log(i)); // 输出0,1,2
}
循环与生成器
复杂循环逻辑可封装为生成器函数,实现惰性求值和更清晰的控制流。
function* paginate(items, pageSize) {
for (let i = 0; i < items.length; i += pageSize) {
yield items.slice(i, i + pageSize);
}
}
for (const page of paginate(allItems, 10)) {
// 每次处理10个元素
}
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:条件语句规范