1. 为什么"传参"通常更好?
✅ 1)意图更清晰
javascript
function calcPrice(count, taxRate) { // 一眼就知道需要啥
return count * 100 * (1 + taxRate);
}
vs
javascript
let taxRate = 0.08;
function calcPrice(count) { // 看不出来还依赖 taxRate
return count * 100 * (1 + taxRate);
}
传参的时候,函数签名就是"需求清单",别人一看就知道这个函数要什么东西。
✅ 2)更好测、更好复用
- 传参:写单测时,随便喂各种参数就能测试。
- 依赖外部变量:你得先改外部变量,或者 mock 环境,麻烦还容易互相干扰。
python
# 传参版
def discount(price, ratio):
return price * ratio
# 外部变量版
RATIO = 0.9
def discount(price):
return price * RATIO
第一个在测试环境里很好搞:
discount(100, 0.5)、discount(100, 0.9) 想测啥测啥。
第二个你要改 RATIO,还小心别影响别的测试用例。
✅ 3)耦合更低
- 使用外部变量 = 函数和外部环境绑得很死。
- 传参 = 函数只关心"输入 → 输出",外部只负责提供数据。
耦合高的坏处:
- 重构时,改一个地方牵一堆东西。
- 多线程/多协程/多请求下可能踩共享数据(尤其是状态可变的时候)。
✅ 4)并发和异步更安全
比如在 JS 里:
javascript
let currentUserId;
async function handleRequest(userId) {
currentUserId = userId;
await someAsyncWork();
log("user: ", currentUserId); // 有可能已经被别的请求改了
}
如果你改成传参:
scss
async function handleRequest(userId) {
await someAsyncWork();
log("user: ", userId); // 永远是自己的
}
不会被其他并发请求污染。
2. 那什么时候可以用"外部作用域变量"?
不是说"外部变量必死罪",只是要用得克制一点。
✅ 适合用外部作用域的场景
-
真正的常量 / 配置,且全局统一
- 比如:
PI、MAX_RETRY、API_BASE_URL这类 恒定不变 的东西。 - 或者配置对象:
config = {...},在多个地方读。
- 比如:
-
工具函数里使用的、明显不应该由调用方决定的东西
比如日志函数里的全局 logger、时间格式器等,这些属于"环境",而不是"业务参数"。
-
闭包做"柯里化"/"部分应用"的时候
这种用外部变量,反而是清晰的设计:
javascriptfunction makeAdder(delta) { return function (x) { return x + delta; // 用外部 delta,很自然 }; } const add10 = makeAdder(10); add10(5); // 15外部变量在这里其实是"构造参数",而返回的函数只暴露一部分参数。
-
避免在层层传递一些"框架级上下文"时,可用 DI / 上下文对象
比如 web 框架里,有类似
requestContext这种东西,可以通过依赖注入、上下文管理器、ThreadLocal 等访问------这些本质上也是"外部作用域变量"的一种(但通常有框架规范来控制滥用)。
3. 什么时候"绝对不要"用外部变量?
-
变量是可变状态(会被改来改去)
- 比如
currentUser,currentOrder,tempList,cacheData等。 - 一改就变"隐形依赖",容易出错、线程不安全。
- 比如
-
函数逻辑高度依赖当前"时刻"的外部状态
- 比如"点按钮时看全局的 selectedItem 是谁"这种,如果逻辑越来越复杂,会很难排错。
-
你自己都开始怀疑"这玩意儿是谁改的?"的时候
- 说明已经失控了 😂
4. 性能上会不会传参更慢?
一般业务代码里:
- 传参的开销 = 微乎其微,可以忽略。
- 把设计搞乱、调试时间翻倍的开销 = 巨大。
除非你在写 极致性能敏感 的底层库(比如内核、编解码核心循环这种),否则别因为"性能"去牺牲可读性和可维护性。
就算是那种场景,也会结合 profiler 真实数据来优化,而不是凭感觉"传参好像慢"。
5. 可以直接拿去用的简单原则
你可以记一个小 checklist:
-
这个值会变吗?
- 会变 → 传参,别用外部变量。
- 不会变(常量/配置)→ 可以外部,但最好集中管理。
-
这个函数能独立拿去写单测吗?
- 如果不能,因为缺这缺那的"外部状态" → 优先改成传参。
-
函数的行为是否能只通过参数来描述?
- 能 → 传参,多爽。
- 不能 → 你可能在做"状态机、上下文管理"这类事,考虑用对象封装、类、context,而不是到处飘全局变量。