在 ESLint 中,此处记录的无参数重新分配规则禁止您分配函数参数的值。
这是为了避免修改函数的arguments
对象。
正确的编码方法是将参数重新分配给本地var
并返回var
。这对于某些类型很好,但对于传递给函数的对象似乎毫无意义。
例如,让我们以这个函数为例;
function foo(param) {
var copy = param; // This makes the linter happy
copy.bar = 2;
console.log('arg 0: ', arguments[0], 'param:', param, 'copy:', copy);
return copy; // A pointless return, the original object has been modified.
}
let test = { bar: 1 };
foo(test);
console.log(test); // Has been modified
test = foo(test); // a pointless reassignment, foo has already changed test.
console.log(test); // Same effect as previous function call.
公平地说,ESLint确实允许您使用/*eslint no-param-reassign: ["error", { "props": false }]*/
关闭此功能;但我不得不想知道为什么?
此规则的要点是摆脱可变性并保持arguments
对象纯洁,但简单的对象重新分配不会这样做。
真正做到这一点的唯一方法是深度克隆参数并将其分配给函数范围的变量。
我在这里错过了什么吗?
将参数分配给变量时它不发出警告的可能原因是它需要复杂的数据流分析。假设你有这样的代码:
function foo(param, flag) {
var copy = flag ? param : {...param};
copy.bar = 2;
console.log('arg 0: ', arguments[0], 'param:', param, 'copy:', copy);
return copy; // A pointless return, the original object has been modified.
}
现在它无法判断copy
是否包含与param
或克隆相同的对象,这取决于flag
的值。
或者像这样:
function foo(param) {
var copy = param;
var copy2 = copy;
var copy3 = copy2;
copy3.bar = 2;
console.log('arg 0: ', arguments[0], 'param:', param, 'copy:', copy3);
return copy3;
}
这需要跟踪整个引用链,以确定copy3
与param
相同。
跟踪这一点并非不可能,优化编译器通常会这样做。但对于一个棉绒来说,这可能是矫枉过正。
Barmar的回答确实切中要害。我仍然在这里添加我的两分钱,因为当涉及到大型代码库时,这条规则非常重要。仅从您的示例开始,ESLint 的工作是指出错误的编码实践。作为开发人员,我们仍然可以在很多方面愚弄棉绒!
解决函数foo
中的 ESLint 错误的正确方法是 -
function foo(param) {
// This makes the linter happy, as well as the codebase :')
const copy = { ...param, bar: 2 };
console.log('arg 0: ', arguments[0], 'param:', param, 'copy:', copy);
return copy; // No modifications to the original object
}
如您所见,不需要参数的深度克隆。
关于你关于为什么这个规则的问题,看看这个在Github上运行的超长线程,讨论你提到的同样的问题 - https://github.com/airbnb/javascript/issues/719。希望它能帮助你学习一些新的和有趣的:)
旁注- 简单地重新分配参数也会使代码难以遵循。这似乎也是一个坏主意,因为它在许多引擎中进行了非优化,特别是 v8。老实说,我仍在阅读更多内容,以更好地理解最后一行。如果您也想阅读此内容,请参阅此处 - https://github.com/airbnb/javascript/issues/641#issuecomment-167827978