调试:ESLint 警告“循环中声明的函数包含对变量的不安全引用...no-loop-func”

roy*_*y05 8 javascript settimeout reactjs eslint create-react-app

使用 Create-React-App [ https://roy-05.github.io/sort-visualizer/ ]在 React 中构建 Sort-Visualizer

我正在使用 setTimeouts 为循环的每次迭代设置动画。在开发控制台上,我收到以下警告:

第 156:32 行:在循环中声明的函数包含对变量 'minimum'、'minimum'、'minimum'、'minimum' 的不安全引用 no-loop-func

这是代码片段:

for(let i=0; i<arr.length-1; i++){
            let minimum = i; //Declare minimum here
            setTimeout(()=>{
                for(let j = i+1; j<arr.length; j++){
                    setTimeout(()=>{
                        //Getting a warning for these references:
                        array_bar[j].style.backgroundColor = 'red';
                        array_bar[minimum].style.backgroundColor = 'blue';
                        setTimeout(()=>{
                            if(arr[j] < arr[minimum]){
                            array_bar[minimum].style.backgroundColor = 'lightblue';
                            minimum = j; 
                            }  
                            else{
                                array_bar[j].style.backgroundColor = 'lightblue';
                            }  
                        }, 4);
                    }, (j-1)*4);    
                }
Run Code Online (Sandbox Code Playgroud)

通过ESLint Docs,我相信问题可能是我正在修改 setTimeout 内的值,但该变量是在其范围之外声明的。

我不确定如何解决该警告,任何帮助将不胜感激!

注意:如果您需要,这里是整个功能 -

selectionSort(){
        const arr = this.state.array,
            array_bar = document.getElementsByClassName("array-elem");

        this.setState({startedSelectionSort: true});

        for(let i=0; i<arr.length-1; i++){
            let minimum = i; //Declare minimum here
            setTimeout(()=>{
                for(let j = i+1; j<arr.length; j++){
                    setTimeout(()=>{
                        //Getting a warning for these references:
                        array_bar[j].style.backgroundColor = 'red';
                        array_bar[minimum].style.backgroundColor = 'blue';
                        setTimeout(()=>{
                            if(arr[j] < arr[minimum]){
                            array_bar[minimum].style.backgroundColor = 'lightblue';
                            minimum = j; 
                            }  
                            else{
                                array_bar[j].style.backgroundColor = 'lightblue';
                            }  
                        }, 4);
                    }, (j-1)*4);    
                }
                setTimeout(()=>{
                    let temp = arr[i],
                    arr1_height = arr[minimum],
                    arr2_height = arr[i];

                    arr[i] = arr[minimum];
                    arr[minimum] = temp;

                    array_bar[i].style.height = `${arr1_height}px`;
                    array_bar[minimum].style.height = `${arr2_height}px`;

                    array_bar[i].style.backgroundColor = "green";
                    if(i !== minimum){
                        array_bar[minimum].style.backgroundColor = 'lightblue';
                    }
                }, 400);


                if(i === arr.length-2){
                    setTimeout(()=>{
                        array_bar[i+1].style.backgroundColor = "green";
                    },800);
                }

            }, i*400);
        }

        setTimeout(()=>{
            this.setState({sorted: true})
        }, arr.length*400+1750);

    }
Run Code Online (Sandbox Code Playgroud)

Gol*_*her 14

我也遇到了同样的警告。就我而言,我在迭代外声明了变量,但在forEach方法内修改了变量。

就像是:

// some code above
let validInputs = true;

someInputs.forEach( input => {
  validInputs = input.value && validInputs;
})
Run Code Online (Sandbox Code Playgroud)

在我做了一些研究之后,我在这篇文章中发现了JSHint 错误:在引用外部作用域变量的循环中声明的函数可能会导致语义混乱,提到JSHint 不喜欢那里的匿名函数如何被重新创建和结束

我将forEach箭头函数更改为for (let index i = 0; index < someInputs.length; index++),警告消失了。

也许在您的情况下,更改setTimeout为传统的非箭头功能可以消除警告。

2021 年 4 月 7 日更新

当我正在阅读Professional JavaScript for Web Developers,第 4 版时,我可能已经发现为什么在 ESLint 中实现了这个警告。

从 4.3 垃圾收集部分,书中提到关闭也可能导致内存泄漏。

为宗旨forEacharrow function是限制变量的范围,如从下面MDN描述:

箭头函数根据定义箭头函数的范围建立“this”。来自箭头函数表达式

在循环中创建闭包:一个常见错误一节中,MDN 提到:

另一种替代方法是使用 forEach() 遍历 helpText 数组并将侦听器附加到 each ,如下所示:

function showHelp(help) {
  document.getElementById('help').textContent = help;
}

function setupHelp() {
  var helpText = [
      {'id': 'email', 'help': 'Your e-mail address'},
      {'id': 'name', 'help': 'Your full name'},
      {'id': 'age', 'help': 'Your age (you must be over 16)'}
    ];

  helpText.forEach(function(text) {
    document.getElementById(text.id).onfocus = function() {
      showHelp(text.help);
    }
  });
}

setupHelp();
Run Code Online (Sandbox Code Playgroud)

在我们的实现中,调用arrow functionsinsideforEach是创建闭包的闭包,这显然会给垃圾收集带来一些令人困惑的语义。

  • `可能会为垃圾收集创建一些令人困惑的语义` - [请不要狡猾](https://en.wikipedia.org/wiki/Weasel_word)。无意冒犯,但这句话听起来像是有人在谈论他们知之甚少的事情。我建议要么就 GC 如何“混淆”做出精确的声明,要么完全删除该声明。在 MDN 示例中,可能会发生内存泄漏,因为该函数被分配给 DOM 节点,这与您的情况非常不同。 (4认同)