在JavaScript中为什么不要修改函数的输入参数
最近,我收到一个合并请求代码,其中多个函数都以同一个对象作为输入参数,将该对象作为共享状态,而有些函数在它们的逻辑中修改该对象的属性。
这种形成的最小抽象如下:
const main = () => {
const obj = { ... }; // 初始化obj的属性
funcA(obj);
funcB(obj);
funcC(obj);
}
// 下面的函数基于obj的属性进行逻辑处理
// 并且根据需要更新obj的一些属性
const funcA = (obj) => { ... }
const funcB = (obj) => { ... }
const funcC = (obj) => { ... }
我没有找到一篇好的文章来解释为什么这是一个不良做法,所以我写了这篇文章来收集这些原因:它让代码难以修改、阅读和测试。
1 它让代码难以改动.如上面的例子所示,这三个函数都依靠共享的 obj
来运作,每个函数都需要 obj
的最新状态。这意味着 funcB
认为 funcA
已经正确设置了或更新了 obj
,而 funcC
则依赖于 funcA
和 funcB
谨慎地修改 obj
,而不影响其他不应修改的属性。换句话说,这些函数紧密相连,并且需要严格的执行顺序。
几周后,如果我们需要在工作流中加入一个 funcD
,我们需要仔细考虑将其放在哪里:它应该放在 funcA
和 funcB
之间,还是应该放在 funcC
后面?如果我们不阅读并跟踪 obj
在所有相关函数中的每处修改情况,就无法确定 funcD
的放置位置而不破坏现有逻辑。
同样,我们能否调整 funcB
和 funcC
的顺序,或者让它们并行执行?没有详细调查,这一点还不清楚。同样地,如果 funcA
本来只改变 obj
的 propA
,我们能否也同时改变 propB
?同样,不完全理解这些内容的话,我们无法预测这会如何影响现有代码的行为。
正如之前提到的,每次要修改这种代码时,必须仔细阅读并彻底理解;否则,改动可能不起作用,或者影响现有代码的行为。
达到这种完全的理解并非易事。仅仅通过查看每一行代码就预测obj
在任意时刻的最新状态是相当困难的。相反,我们必须从头到尾跟踪代码,跟随每一个if…else
分支和嵌套的函数调用,以理解obj
何时被访问、使用了什么值、何时被修改以及原因。
任何误解或忽略条件都可能导致严重的逻辑混淆,从而导致在如何使用或与现有代码互动时做出糟糕的决定。每个函数中的逻辑分支越多,整个代码的行为就越难以理解,所需的理解和阅读时间也会增加。
3 这使得代码难以进行测试为了评估测试一个函数难度,让我们考虑最简单的例子:纯粹的函数。对于已知输入,我们可以简单地检查输出是否符合预期。
当我们使用一个共享的 obj
,它有许多属性时,我们必须考虑到所有可能的属性组合,以覆盖不同的分支。
尤其是如果 obj
的某些属性在每个函数中并没有被明确使用,这样一来,测试用例的设计会变得非常复杂:我们是否应该为未使用的属性分配随机值?若有些属性是隐式使用的(例如,通过反射、运行时动态属性访问,或传递给嵌套函数或第三方库),又该怎么办?
除此之外,这些函数修改输入的 obj
而不是返回结果,因此哪些属性应该被修改而哪些不应该被修改就变得非常不清楚。此外,因为这些更改通常是基于条件的,很容易忽略一些边界条件的检查。
请避免在JavaScript中修改函数的输入参数,这样会使代码难以更改、理解和测试。
简单英语感谢你加入__In Plain English网站_!在你离开之前,想对你说:
- 记得给作者点赞并关注👏️
- 关注我们:X | 领英网 | YouTube | Discord | 简报 | 播客节目
- 免费在Differ上创建一个AI驱动的博客。Create a free AI-powered blog on Differ.
- 更多内容,请访问PlainEnglish.io
共同学习,写下你的评论
评论加载中...
作者其他优质文章