Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is ESlint happy for me to modify object properties as long as the object is reassigned? no-param-reassign

In ESLint, the no-param-reassign rule as documented here, forbids you from assigning the value of a function param.

This is to avoid having a function's arguments object be modified.

The correct way to code is to reassign the param to a local var and return the var. This is fine for some types, but it seems pointless for objects passed to a function.

For example, let's take this function;

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.

To be fair, ESLint does allow you to turn this feature off with /*eslint no-param-reassign: ["error", { "props": false }]*/; but I have to wonder why?

The point of this rule is to get rid of mutability and keep the arguments object pure, but a simple reassignment of an object will not do this.

The only way to truly do that would be to deep clone the param and assign that to a function scoped variable.

Am I missing something here?

like image 372
Christie Avatar asked Oct 15 '25 16:10

Christie


1 Answers

The likely reason that it doesn't warn when you assign the parameter to a variable is that it would require complex data flow analysis. Suppose you have code like this:

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

Now it can't tell whether copy contains the same object as param or a clone, it depends on the value of flag.

Or something like this:

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

This would require keeping track of the entire chain of references to determine that copy3 is the same as param.

Tracking this isn't impossible, optimizing compilers often do it. But it may be overkill for a linter.

like image 134
Barmar Avatar answered Oct 17 '25 04:10

Barmar



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!