Array.prototype.includes中的错误?

时间:2019-05-05 11:54:37

标签: javascript arrays node.js v8

在一种情况下,我遇到了Array.prototype.includes的奇怪行为。

鉴于Array.prototype.includes在绑定上下文中有效,有人可能会这样使用(有效)

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

简单地说,我们绑定数组[1, 2]并测试1是否包含。

然后考虑,许多Array.prototype方法都能够将上下文绑定到所提供的回调,因此例如Array.prototype.some可以与Object.prototype.hasOwnProperty结合使用

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

此处,.some接受两个参数(callback, [thisArg]),其中可选的thisArg(如果提供)绑定到回调,因此上一示例将{ foo: 0 }绑定到回调{{1 }},然后测试Object.prototype.hasOwnProperty中的所有项目,如果至少一项是["foo", "bar"]的财产。这个例子也可以。

但是,如果您尝试使用{ foo: 0 }作为回调,则会发生一些奇怪的事情。

Array.prototype.includes

在这里,我们将数组[0, 1].some(Array.prototype.includes, [1]) // => false 绑定到[1],并且测试Array.prototype.includes的每一项是否包含至少一项。但是此案例返回false,这与我们的预期相反。

奇怪的是,如果绑定数组包含除[0, 1]以外的其他数字或包含多个项,则测试通过了

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 的处理不正确。

已在 节点v.11.11.0 节点v.8.11.3 和Chrome 73

我基本上只测试了V8引擎。谁能报告脉轮的输出?

1 个答案:

答案 0 :(得分:14)

这不是includes中的错误。 :-)

问题是includes接受一个可选的第二个参数,即开始搜索的索引,而some为回调提供了三个参数:项目,其索引和对象被搜索。

所以

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

进行这些通话(有效):

  • [1].includes(0, 0)-否,该数组不包含0
  • [1].includes(1, 1)-否,该数组在索引1处包含0,但是搜索从索引1
  • 开始

这会定期出现。例如,由于parseInt的第二个参数(要使用的基数或基数),当尝试使用parseInt作为直接将字符串数组转换为数字数组的回调时:

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

97失败,因为调用是(有效地):

  • parseInt("6", 0)-之所以起作用,是因为parseInt会忽略无效的基数0
  • parseInt("9", 1)-NaN,因为parseInt总是返回NaN的基数1
  • parseInt("7", 2)-NaN,因为"7"不是以2为底的有效数字(二进制​​)

故事的寓意:请记住mapsomeforEach和其他各种方法提供给回调的不常用参数。 :-)


在我正在使用的一个代码库中,他们有一个clamp函数,该函数接受一个函数,并确保无论调用了多少参数,它都只会传递所需数量的参数。如果您经常使用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

方便的事情是includes是可重用的。

当然,也可以使用包装函数:

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


当然,所有这些

都是 general 解决方案。如果您特别想知道数组a是否包含数组b中的任何条目,则可以根据a和{的特征,构建一些更具体的实现来有效地处理该实现。 {1}}。