布尔标志位实现单次执行函数的关键是状态隔离与无锁判断,通过闭包封装独立flag,首次调用执行并置false,后续直接返回,性能接近裸指针访问。

用布尔标志位实现单次执行函数,关键在于“状态隔离”和“无锁判断”。它不依赖系统级同步原语(如 std::once_flag),适合轻量、高频、单线程或明确无竞态的场景,性能接近裸指针访问。
核心结构:闭包内封装 flag + 执行体
把布尔变量定义在闭包作用域中,确保每次调用该闭包工厂函数都生成独立的执行上下文。flag 初始化为 true,首次调用时执行逻辑并立即将其设为 false;后续调用直接返回,不进入任何分支逻辑。
- 闭包外不可见 flag,避免外部误改
- flag 存储在堆/栈上由 JS 引擎或编译器自动管理,无手动内存操作
- 判断仅一次布尔读取 + 一次条件跳转,指令极简
JavaScript 示例:简洁可靠的 once 包装器
以下函数返回一个只执行一次的目标函数:
const once = (fn) => {let called = false;
return function(...args) {
if (called) return;
called = true;
return fn.apply(this, args);
};
};
// 使用
const init = once(() => console.log('初始化完成'));
init(); // 输出:初始化完成
init(); // 无输出
C++ Lambda 版本:值捕获 + mutable
利用 mutable 允许修改值捕获的局部变量,保持闭包纯净性:
if (called) return;
called = true;
fn();
};
注意:此处用 static 是为演示;若需多个独立 once 实例,应改用非 static 成员变量或类封装 —— 否则所有调用共享同一 flag。
性能关键点:避免常见低效写法
- 不用对象属性(如
{ called: false })替代原始布尔值 —— 多一次属性查找开销 - 不把 flag 放在全局或模块顶层(除非明确需要跨闭包共享)—— 破坏封装且易被干扰
- 不在判断中调用 getter 或计算属性 —— 布尔读取必须是原子、零成本操作
- 避免用
undefined/null检查模拟 flag —— 类型判断比布尔判断更重










