Javascript 为什么只要对象被重新分配,ESlint就乐于修改对象属性?无参数重新分配

Javascript 为什么只要对象被重新分配,ESlint就乐于修改对象属性?无参数重新分配,javascript,eslint,Javascript,Eslint,在ESLint中,文档中的无参数重新分配规则禁止您分配函数param的值 这是为了避免修改函数的参数对象 正确的编码方法是将参数重新分配给本地var,并返回var。对于某些类型来说,这很好,但对于传递给函数的对象来说,这似乎毫无意义 例如,让我们以这个函数为例 function foo(param) { var copy = param; // This makes the linter happy copy.bar = 2; console.log('arg 0: ',

在ESLint中,文档中的无参数重新分配规则禁止您分配函数param的值

这是为了避免修改函数的
参数
对象

正确的编码方法是将参数重新分配给本地
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}]*/
关闭此功能;但我想知道为什么

此规则的要点是消除可变性并保持
参数
对象的纯粹性,但简单地重新分配对象不会做到这一点

真正做到这一点的唯一方法是深度克隆参数并将其分配给函数范围的变量


我在这里遗漏了什么吗?

当您将参数分配给变量时,它不会发出警告的可能原因是它需要复杂的数据流分析。假设您有如下代码:

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.
}
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;
}
现在它无法判断
copy
是否包含与
param
相同的对象或克隆,这取决于
标志的值

或者像这样:

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.
}
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
相同


跟踪这一点并非不可能,优化编译器通常可以做到这一点。但对于一根短绒来说,这可能是矫枉过正了。

巴尔马的回答确实切中要害。我还在这里加上我的两分钱,因为这条规则对于大型代码库来说非常重要。仅从您的示例开始,ESLint的工作就是指出错误的编码实践。作为开发人员,我们仍然可以在许多方面愚弄linter

解决函数
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上的这个超长线程,讨论与您提到的相同的问题-。希望它能帮助你学到新的有趣的东西:)


旁注-简单地重新分配参数也会使代码难以理解。这似乎也是一个坏主意,因为它在许多发动机,特别是v8发动机上进行了去优化。老实说,为了更好地理解这最后一行,我还在读更多关于这方面的文章。如果您也想了解这一点,请参见此处-

函数(optionalArray,callback){if(typeof optionalArray=='function'){callback=optionalArray;}doSomeAsyncStuff();callback();}
--我在野外看到的代码它可能没有足够的数据流分析来确定修改时
copy
是否仍然引用参数。
{“props”:false}
是默认值。我不建议设置
{“props”:true}
,因为它几乎捕捉不到任何东西(如您所示),而且它捕捉到的东西是完全正常的。@Barmar我们使用的是AirBnB linter规则,它们已经启用了它。我只是想知道启用它的背后是否有合理的理由。我想也许我是对的,在修改对象属性时警告重新分配是没有意义的(除非目的是让人们克隆所有内容而不是仅仅重新分配)。这并不令人高兴。这太愚蠢了,不能为此而悲伤。