在一种情况下,我遇到了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引擎。谁能报告脉轮的输出?
答案 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));
9
和7
失败,因为调用是(有效地):
parseInt("6", 0)
-之所以起作用,是因为parseInt
会忽略无效的基数0
。parseInt("9", 1)
-NaN
,因为parseInt
总是返回NaN
的基数1
parseInt("7", 2)
-NaN
,因为"7"
不是以2为底的有效数字(二进制) 故事的寓意:请记住map
,some
,forEach
和其他各种方法提供给回调的不常用参数。 :-)
在我正在使用的一个代码库中,他们有一个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}}。