【问题标题】:JavaScript - My function only triggers once while being called several times in a loopJavaScript - 我的函数在循环中被多次调用时只触发一次
【发布时间】:2019-02-23 02:11:30
【问题描述】:

我有这个功能:

  function simplifyString (string)
  {
    var charsToFind = new Array(/[áàâãä]/g, /[éèêë]/g, /[íìîï]/g, /[óòôõö]/g, /[úùûü]/g, /ç/g, /[-  \'&_]/g),
        charsToReplace = new Array('a', 'e', 'i', 'o', 'u', 'c', '');

    string = string.toLowerCase();

    for (i = 0; i < charsToFind.length; i++)
    {
      string = string.replace(charsToFind[i], charsToReplace[i]);
    }

    return string;
  }

我在循环中使用它,如下所示:

for (i = 0; i < objects.length; i++)
{
  var value = simplifyString(objects[i].innerText);
  
  console.log(value);
  console.log(i);
 }

Objects 变量包含一个元素数组。

控制台只会显示第一个元素的内部文本,i 会显示我的数组的长度 - 1。

如果我删除函数的循环,控制台将显示每个对象的内部文本和正确的数字序列。

我不太明白这种行为,有什么帮助吗?

【问题讨论】:

  • 您可能会将i 泄漏到不同的范围内。
  • 您能否显示更多代码。
  • 我肯定被重新分配了!在 simpleString 函数中。如果你只是做 var 1 = 0,我想你会没事的。没有 var 将其设置为全局变量。
  • @MaheerAli 没有更多可展示的了。我只是用 JQuery 得到一组对象:var objects = $('span')
  • 是的,你们是对的,我在我的函数中声明了i,它现在可以工作了。没想到。非常感谢,这让我发疯了

标签: javascript regex loops


【解决方案1】:
for (i = 0; i < objects.length; i++)
for (i = 0; i < charsToFind.length; i++)

到...

for (var i = 0; i < objects.length; i++)
for (var i = 0; i < charsToFind.length; i++)

或者...

for (let i = 0; i < objects.length; i++)
for (let i = 0; i < charsToFind.length; i++)

关于浏览器支持的注意事项:在 IE 11 中“让变量不单独绑定到 for 循环的每次迭代” Caniuse - let.

您当前在两个for 循环中声明i,没有标识符var, let, const,因此它被分配给global object 上的相同i 属性,而不是声明一个新的局部范围变量。 simplifyString (string) 内的 for 循环将新值分配给与第一个 for 循环相同的 i 并将所有内容都搞砸了。


* 如 cmets 中所述,这就是您如何使用 reduce() 使您的代码更具可读性、减少不必要的 side-effects/mutations 并将您的 tests 直接与它们的替换 values 耦合以避免一些混淆...

var charReplacements = [
   { test: /[áàâãä]/g,   value: 'a' },
   { test: /[éèêë]/g,    value: 'e' },
   { test: /[íìîï]/g,    value: 'i' },
   { test: /[óòôõö]/g,   value: 'o' },
   { test: /[úùûü]/g,    value: 'u' },
   { test: /ç/g,         value: 'c' },
   { test: /[-  \'&_]/g, value: ''  }
];

function simplifyString (string) {    
    return charReplacements
              .reduce((str, {test, value}) => 
                 str.replace(test, value)
              , string);
}

注意:如果您在大型数据集上运行此程序,我会问比我更聪明的人如何使用几行正则表达式来执行此操作,这比迭代替换器更有效

【讨论】:

  • 我实际上更喜欢现在尽可能使用较新的 Array 方法(forEach()map()reduce().etc)。从句法上讲,它们更简洁,更易读,性能开销很小(在小型数据集上可以忽略不计)。当你有机会时,你应该看看那些。
  • 我在函数中使用了for,因为我需要索引才能使我的两个数组匹配。在第二个循环中,我确实没有特别的理由使用它。 forEach 循环肯定会完成这项工作。我听说过 map() 和 reduce(),但从未深入了解它们。我一定会的。感谢您的提示!
  • 哇,我喜欢这个。这看起来更现代、更专业、更易读,同时也更短。在我看到你的帖子之前,我实际上是在用数组和 reduce()/map() 循环进行一些测试。从现在开始,我将使用它并尝试使用这些工具进行编码。我倾向于坚持我所知道的,因为它更舒服,而且新事物对我来说似乎令人困惑,但这肯定会有所帮助。我还学习了箭头函数,真的,谢谢。
  • 太棒了!很高兴我能提供帮助,并认为这是一个很好的方向。根据您所处的环境(尤其是解构{test, value}),您必须小心使用其中一些较新的语言功能。这 2 门课程非常棒地介绍了以类似方式处理复杂数据集...Asynchronous Programming in JavaScript (with Rx.js Observables)Advanced Asynchronous JavaScript
【解决方案2】:

问题在于循环计数器的范围。 而不是做

for (i = 0; ...)

你应该将你的循环计数器声明为

for (let i = 0;...)

所以它的范围是你的循环块。

如果您将循环变量声明为“i=0”,则“i”具有全局范围。在这种情况下,您在simplifyString 循环中使用的“i”与您在调用simplifyString 的循环中使用的“i”相同!由于第一次调用时,simplifyString 会增加 'i',因此调用循环会提前终止。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-05-06
    • 2021-12-06
    • 2014-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-08
    • 2019-01-30
    相关资源
    最近更新 更多