简体   繁体   English

Array.prototype.includes中的错误?

[英]Bug in Array.prototype.includes?

I encountered strange behavior of Array.prototype.includes in one edge case. 我在一个边缘情况下遇到了Array.prototype.includes奇怪行为。

Given that Array.prototype.includes works on bound context, one might use it like this (which is working) 鉴于Array.prototype.includes对绑定上下文有效,可以像这样使用它(它正在工作)

expect(Array.prototype.includes.call([1, 2], 1))).toBe(true)

simply put, we bound array [1, 2] and test 1 for inclusion. 简单地说,我们绑定数组[1, 2]和测试1包含。

Then consider, that many Array.prototype methods are able to bound context to provided callback, so for example Array.prototype.some can be combined with Object.prototype.hasOwnProperty like this 然后考虑一下,许多Array.prototype方法能够将上下文绑定到提供的回调,因此例如Array.prototype.some可以与Object.prototype.hasOwnProperty结合使用,就像这样

expect(["foo", "bar"].some(Object.prototype.hasOwnProperty, { foo: 0 })).toBe(true)

Here, .some accepts two parameters, (callback, [thisArg]) , where optional thisArg , when provided, is bound to callback, thus previous example binds { foo: 0 } to callback Object.prototype.hasOwnProperty and then tests all items in ["foo", "bar"] if at least one is own property of { foo: 0 } . 这里, .some接受两个参数, (callback, [thisArg]) ,其中可选thisArg ,如果提供,则绑定到回调,因此前面的示例将{ foo: 0 }绑定到回调Object.prototype.hasOwnProperty ,然后测试所有项目["foo", "bar"]如果至少有一个是{ foo: 0 }自有属性。 This example is also working. 这个例子也有效。

But something strange happen, if you try to use Array.prototype.includes as callback. 但是如果你尝试使用Array.prototype.includes作为回调,那么会发生一些奇怪的事情。

[0, 1].some(Array.prototype.includes, [1]) // => false

here we bind array [1] to Array.prototype.includes and we test every item of [0, 1] if at least one is included. 这里我们将array [1]绑定到Array.prototype.includes ,如果包含至少一个,我们测试[0, 1]每个项目。 But this case returns false, which is against our expectation. 但这种情况会返回false,这违背了我们的预期。

Strangely, if bound array contains other number than 1 or contains more than one item, the test passes 奇怪的是,如果绑定数组包含除1以外的其他数字或包含多个项目,则测试通过

[0, 1].some(Array.prototype.includes, [0]) // => true
[0, 1].some(Array.prototype.includes, [1, 1]) // => true
// but
[0, 1].some(Array.prototype.includes, [1]) // => false

It seems like array [1] is handled improperly. 似乎数组[1]处理不当。

Tested in Node v.11.11.0 Node v.8.11.3 and Chrome 73 在Node v.11.11.0 Node v.8.11.3和Chrome 73中测试

I tested basically just V8 engine. 我基本上只测试了V8发动机。 Can anyone report output in Chakra? 任何人都可以在Chakra报告输出吗?

It's not a bug in includes . 这不是一个错误includes :-) :-)

The problem is that includes accepts an optional second parameter, which is the index at which to start searching, and some provides three arguments to its callback: The item, its index, and the object being searched. 问题是includes接受一个可选的第二个参数,它是开始搜索的索引, some参数为其回调提供了三个参数:项目,索引和被搜索的对象。

So with 所以

[0, 1].some(Array.prototype.includes, [1])

These calls are made (effectively): 这些调用是(有效地):

  • [1].includes(0, 0) - false, the array doesn't contain 0 [1].includes(0, 0) - false,数组不包含0
  • [1].includes(1, 1) - false, the array contains 1 at index 0 , but the search starts at index 1 [1].includes(1, 1) - false,数组在索引0处包含1 ,但搜索从索引1开始

This comes up periodically. 这会定期出现。 For instance, when trying to use parseInt as a callback directly to convert an array of strings into an array of numbers, because of parseInt 's second parameter (the number base, or radix, to use): 例如,当尝试使用parseInt作为回调直接将字符串数组转换为数字数组时,因为parseInt的第二个参数(要使用的数字基数或基数):

 console.log(["6", "9", "7"].map(parseInt)); 

The 9 and 7 fail becaue the calls are (effectively): 97失败,因为呼叫是(有效):

  • parseInt("6", 0) - works because parseInt ignores the invalid radix 0 . parseInt("6", 0) - 有效,因为parseInt忽略无效的基数0
  • parseInt("9", 1) - NaN because parseInt always returns NaN for radix 1 parseInt("9", 1) - NaN因为parseInt总是为基数1返回NaN
  • parseInt("7", 2) - NaN because "7" is not a valid digit in base 2 (binary) parseInt("7", 2) - NaN因为"7"不是基数2(二进制)中的有效数字

The moral of the story : Remember the not-commonly-used arguments that map , some , forEach , and various other methods provide to callbacks. 故事的寓意 :记住不常用的参数,即mapsomeforEach和各种其他方法提供给回调。 :-) :-)


In one codebase I was working in, they had a clamp function that accepted a function and ensured that, regardless of how many arguments it was called with, it would only pass on the desired number of arguments. 在一个代码库,我的工作中,他们有一个clamp ,也是接收功能,并确保,不管是多少个参数调用,它只会传递参数的所需数量的功能。 If you were using includes like this a lot, you could create a clamped includes : 如果您使用这样的includes很多,您可以创建一个includes

 function clamped(fn, count) { return function(...args) { return fn.apply(this, args.slice(0, count)); } } const includes = clamped(Array.prototype.includes, 1); console.log([0, 1].some(includes, [1])); // true console.log([0, 1].some(includes, [3])); // false 

The handy thing about that is that that includes is reusable. 关于这一点的便利之处在于includes可重复使用。

Or of course, just use a wrapper function: 或者当然,只需使用包装函数:

 console.log([0, 1].some(function(entry) { return this.includes(entry); }, [1])); // true console.log([0, 1].some(function(entry) { return this.includes(entry); }, [3])); // false 


These are all meant to be general solutions, of course. 当然,这些都是通用的解决方案。 If you specifically want to know if array a contains any of the entries in array b , there are more specific implementations you can build to handle that efficiently depending on the characteristics of a and b . 如果您特别想知道数组a包含数组b中的任何条目,那么您可以构建更具体的实现来根据ab的特性有效地处理它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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