【问题标题】:Why is ESlint happy for me to modify object properties as long as the object is reassigned? no-param-reassign为什么只要重新分配对象,ESlint 就乐意让我修改对象属性?无参数重新分配
【发布时间】:2019-02-05 22:10:51
【问题描述】:

在 ESLint 中,here 中记录的 no-param-reassign 规则禁止您分配函数参数的值。

这是为了避免修改函数的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(optionalArray,callback){if (typeof optionalArray === 'function') { callback = optionalArray; } doSomeAsyncStuff(); callback();} -- 我在野外看到的代码
  • 可能没有足够的数据流分析来判断copy在修改时是否仍然引用参数。
  • { "props": false } 是默认值。我不建议设置{ "props": true },因为它几乎无法捕获任何东西(如您所展示的),而且它捕获的东西是完全正常的事情。
  • @Barmar 我们正在使用 AirBnB linter 规则,他们已启用它。只是想知道启用它是否有一些合理的理由。我想也许我是对的,在修改对象属性时警告重新分配是没有意义的(除非目的是让人们克隆所有东西而不仅仅是重新分配)。
  • 不开心。太愚蠢了,不能为此感到难过。

标签: javascript eslint


【解决方案1】:

将参数分配给变量时它不发出警告的可能原因是它需要复杂的数据流分析。假设你有这样的代码:

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;
}

这需要跟踪整个引用链以确定copy3param 相同。

跟踪这不是不可能的,优化编译器经常这样做。但这对于 linter 来说可能有点过头了。

【讨论】:

    【解决方案2】:

    Barmar 的回答很中肯。我仍然在这里加两分钱,因为这条规则对于大型代码库非常重要。仅从您的示例开始,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 上运行的超长线程,讨论你提到的同样的问题 - https://github.com/airbnb/javascript/issues/719。希望它可以帮助您学习一些新的有趣的东西:)

    旁注 - 简单地重新分配参数也会使代码难以遵循。这似乎也是一个坏主意,因为它在许多引擎中进行了优化,特别是 v8。老实说,我仍在阅读更多关于这方面的内容,以更好地理解最后一行。如果您也想阅读此内容,请参阅此处 - https://github.com/airbnb/javascript/issues/641#issuecomment-167827978

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-05-10
      • 1970-01-01
      • 2020-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-02
      相关资源
      最近更新 更多