简体   繁体   中英

Why is an If statement considered a function in this loop?

I have been building a React app that uses iteration a lot. I am using JSLint and get the annoying warning saying:

Don't make functions within a loop

On the following loop:

if(currentSearch[i].users.length > 0) {
    var matched = false;

    //I hate how JSLint just can't handle setting a variable to true within a function
    //this is loop where I get the warning 
    currentSearch[i].users.some(childUser => {
        if(childUser.id === user.id) {
            return matched = true;
        }
    })
    //^^^^^ Warning

    if(!matched) {
        var alert = new AlertObject(user,currentSearch[i],true,false);
        alerts.push(alert);
    }
}

I don't think I set a function in the loop? I am using the array.some function which will break the loop if I return true, which is what I do. I return a variable, declared outside of the loop, as true. This breaks me out of the loop, and allows me to do logic below.

I should also be noted that this is also entirely within a loop, as we are iterating over current search users. I get no runtime or compile errors, and this code works fine, but maybe I am setting myself up for disaster in the future.

Any ideas why I am getting this error? And if I am missing some best practice?

Since in the first line you reference currentSearch[i] , because the [i] I assume the whole block of code you pasted here is inside some kind of loop, probably a for .

Then, you are creating a function for the Array.some callback, which triggers the error.

One solution would be to move that callback declaration to be outside the parent loop, but since you are using a variable from the scope, it will require some refactor.


Posible solution

You can declare a function outside the parent loop (the one outside the code you provided here) that checks for the child user.

//Please provide a better name for the function according to the context.
const checkChildUser = function (childUser) {
    return this.id === childUser.id;
};

And then pass it to the Array.some function you are using:

currentSearch[i].users.some(checkChildUser, user);

I'm not familiar with React, but this looks like an ES6 arrow function:

childUser => { ... }

Which would be the equivalent of

function (childUser) { ... }

Well, you are providing a function in your .some() as a parameter so thats what triggers the warning.

The reason ESLint warns against it

Writing functions within loops tends to result in errors due to the way the function creates a closure around the loop - source

You can do it like this

function compareId(childUser) {
  if (childUser.id === user.id) {
    return true;
  }
}

if (currentSearch[i].users.length > 0) {
  var matched = currentSearch[i].users.some(compareId);

  if (!matched) {
    var alert = new AlertObject(user, currentSearch[i], true, false);
    alerts.push(alert);
  }
}

In your snippet, the Don't make functions within a loop warning is not caused by the if statement , but by this following anonymous function:

childUser => {
 if(childUser.id === user.id) {
  return matched = true;
 }
}

Since you've said that the entire code is within a loop, a new instance of that anonymous function is being created for every iteration. This will affect the performance.

The problem here is that you create a function that modifies the matched variable. This variable is declared with var , so it's scope is the whole function, not a single loop iteration. This could lead to surprising results, since functions created in each iteration will actually refer to the same variable.

Simply using the value returned by some() instead of changing matched in the callback (as suggested by Yury Tarabanko) should remove the warning.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM