写代码的时候,经常遇到需要根据某个状态做不同处理的情况。比如用户登录了显示“退出”,没登录显示“登录”。这时候不少人会下意识定义一个 flag 变量,像 isLogin 或者 hasData,然后在条件判断里用它控制流程。
flag 变量的常见用法
比如在一个函数里,我们想判断一组数据有没有满足条件的项:
let found = false;
for (let i = 0; i < list.length; i++) {
if (list[i].status === 'active') {
found = true;
break;
}
}
if (found) {
console.log('找到了激活项');
} else {
console.log('没有激活项');
}
这种写法很直观,也容易理解。flag 变量像是个记号,告诉后面的人“这里发生过什么”。
但 flag 容易让逻辑变“重”
问题出在维护上。当函数变长、分支变多,flag 被反复赋值,甚至多个 flag 交织在一起时,读代码的人就得一边看上下文,一边在脑子里记这些 flag 的当前状态。就像你做饭时贴了五张便签条提醒自己“盐加了吗”“水开了吗”“锅盖盖了没”,看得人眼花。
比如下面这种情况:
let isValid = true;
let isProcessed = false;
let hasError = false;
if (data) {
isValid = validate(data);
if (isValid) {
isProcessed = true;
} else {
hasError = true;
}
}
if (isValid && isProcessed && !hasError) { ... }
三个变量纠缠在一起,光是理清它们的关系就要花点时间。其实这些状态本可以通过函数拆分或直接返回结果来简化。
更轻的替代方式
上面那个查找 active 项的例子,完全可以直接用数组方法:
const hasActive = list.some(item => item.status === 'active');
if (hasActive) {
console.log('找到了激活项');
} else {
console.log('没有激活项');
}
逻辑更清晰,变量少了一个。甚至可以更进一步,把判断封装成函数:
function hasActiveItem(list) {
return list.some(item => item.status === 'active');
}
调用的时候一眼就知道意图,不需要再猜 flag 是谁设的、什么时候变的。
flag 不是原罪,滥用才是
flag 变量本身没有错,在循环中断场景、状态机、异步流程控制中都有合理用途。比如轮询接口直到拿到结果:
let finished = false;
while (!finished) {
const res = await checkStatus();
if (res.done) {
finished = true;
} else {
await sleep(1000);
}
}
这种时候 flag 就是个实用的控制开关。关键在于:这个 flag 是否让代码更容易理解?还是反而成了需要额外解释的负担?
如果一个 flag 只出现两次——一次定义,一次使用,那它可能是合理的。但如果它在多个条件里来回跳,被反复修改,或者名字模糊(比如叫 flag1),那就该考虑重构了。
从生活角度看代码
这有点像家里开关灯。你在客厅按一下开关,灯亮了,这个“开”状态就是个 flag。但如果全屋十个房间都靠一个总开关控制,你想关厨房灯还得先摸清楚现在哪些房间开着灯,那就乱套了。代码里的 flag 也是,单一职责才好管。
与其堆一堆 flag,不如多拆几个小函数,用函数名表达意图。代码读起来更像句子,而不是解谜游戏。