为什么原生JS FILTER函数会改变它的输出

Why does the native JS FILTER function vary its output

本文关键字:改变 输出 函数 原生 JS FILTER 为什么      更新时间:2023-09-26

我使用本机JS FILTER函数有以下情况:

var array = ['hello', 'you', 'hello', 'you', 'hello', 'you', 'hello', 'you', 'hello', 'you', 'hello', 'you', 'hello', 'you', 'hello'];
var regex = new RegExp( "hello", "gi" );
function allMatches( item, index, array ){
  return this.test( item );
}

现在像这样运行…

array.filter( allMatches, regex ).length;
=> 7 // should be 8.

注意:传入allMatches函数的所有8项都返回true,但是数组缺少一个项。

现在让我们按照下面的描述更正allMatches函数。

 var array = ['hello', 'you', 'hello', 'you', 'hello', 'you', 'hello', 'you', 'hello', 'you', 'hello', 'you', 'hello', 'you', 'hello'];
// NO LONGER USE THIS var regex = new RegExp( "hello", "gi" );
function allMatches( item, index, array ){
  return /hello/gi.test( item );
}

现在像以前一样运行…

array.filter( allMatches ).length;
=> 8 // as it should be.

请注意所有示例中的以下项目…

  1. 每次迭代THIS是正则表达式,因为它应该是。
  2. 每个应该为TRUE的迭代都为TRUE,这意味着所有8个
  3. THIS始终是正确的正则表达式。

我不是在寻找如何使这项工作,因为我知道一种方法来做到这一点。我想知道为什么会发生这种情况,这样我就可以避免在未来的问题。

下面是使用以下函数

的更多尝试
var regex = new RegExp( "hello", "gi" ); // as before
function allMatches( item, index, array ){
  return this.test( item );
}
array.filter( allMatches, regex ).length;
=> 7 // again, NOT correct.
array.filter( allMatches, /hello/gi ).length;
=> 8 // correct. Passing a regex litteral.
array.filter( allMatches, new RegExp( "hello", "gi" )).length;
=> 8 // correct. Passing the same regexp from 

这里是相同的不工作的例子,但有一个引用的regex文字。var nonConstructorRegex =/hello;

array.filter( allMatches, nonConstructorRegex ).length;
=> 7 // NOT correct.

注意:我认为它与传递给regex的引用有关,但是使用引用的regex文字可以工作,而从构造函数构建的新RegExp变量则不行。请看上面的第一条。

当结果不正确时,它将第一个HELLO计数为false,它应该是TRUE

当regex值作为引用传入时可能会发生。当regex(无论是构造的还是文字的)传入时,不需要引用。

会不会只是时间问题??

从答案中学习了MDN参考后,我明白了为什么。

的例子查找连续匹配

如果您的正则表达式使用"g"标志,您可以多次使用exec()方法来查找同一字符串中的连续匹配。当您这样做时,搜索从正则表达式的lastIndex属性指定的str的子字符串开始(test()也将推进lastIndex属性)。例如,假设您有以下脚本:

var myRe = /ab*/g;
var str = 'abbcdefabh';
var myArray;
while ((myArray = myRe.exec(str)) !== null) {
  var msg = 'Found ' + myArray[0] + '. ';
  msg += 'Next match starts at ' + myRe.lastIndex;
  console.log(msg);
}

如何用我的例子测试这个想法…

var array = ['hello', 'hello', 'hello', 'hello'];
var regex = new RegExp( "hello", "gi" );
function allMatches( item, index, array ){
  console.log(this.lastIndex) 
 return this.test( item );
}
array.filter( allMatches, regex ).length;
=> 2.

每次迭代将console.log。lastindex的累计位置。

因此,第一项将导致。lastindex 5作为字符串"hello"的第5个位置。

下一个hello会命中,但是. lastindex将位于位置5。.test()函数将检查字符串是否与正则表达式匹配,但在5位置。这将导致0,从而将. lastindex重置为0。

第三次迭代将从0开始,并检查hello是否匹配正则表达式,

第4次迭代将到达

,但. lastindex将再次设置在5位置,因此我们将继续执行此操作,直到数组结束,在本例中为

因此…

MUSTARD上校,在衣帽间,挂着"g"旗!!

这与.filter()没有太大关系。

当你在正则表达式中包含"g"标志时,那么每次调用.test()将执行源字符串的搜索,如果找到匹配,它将设置RegExp对象上的.lastIndex属性的值为源字符串的索引,下一个搜索应该从哪里开始。

当您在过滤器函数中使用正则表达式字面量时,这无关紧要,因为对该函数的每次调用都会创建一个新的RegExp实例。但是,当您在连续调用中重用正则表达式时,.lastIndex的值将产生影响。

你张贴的样本,与字符串交替匹配和不匹配的数组,不会显示任何明显的问题。然而,如果您在一行中有两个"hello"字符串,那么它会,因为在匹配第一个字符串之后,.lastIndex的值将是5,所以当.test()被调用用于下一个字符串时,搜索将从字符串的末尾开始并失败。

底线:去掉"g"标志