在尝试使用高阶函数与字符串方法时,我遇到了一个奇怪的问题。这会抛出一个错误:
['a', 'b'].some('boo'.includes)
为了使它起作用,我必须将谓词包装在另一个函数中。但是'boo'.includes
不已经是一个函数吗?
这适用于普通函数:
const boo = {
includes: () => true
};
['a', 'b'].some(boo.includes)
有没有一些特殊的字符串方法属性阻止它们像这样被组合?
在尝试使用高阶函数与字符串方法时,我遇到了一个奇怪的问题。这会抛出一个错误:
['a', 'b'].some('boo'.includes)
为了使它起作用,我必须将谓词包装在另一个函数中。但是'boo'.includes
不已经是一个函数吗?
这适用于普通函数:
const boo = {
includes: () => true
};
['a', 'b'].some(boo.includes)
有没有一些特殊的字符串方法属性阻止它们像这样被组合?
"boo".includes
"就是String.prototype.includes
。不过,当它在字符串“boo”上调用时,会将this
设置为“boo”,这给函数提供了适当的上下文。例如,"boo".includes("b")
等同于String.prototype.includes.call("boo", "b")
。['a', 'b'].some('boo'.includes)
,与['a', 'b'].some(String.prototype.includes)
相同,但缺少适当的this
上下文。bind
:['a', 'b'].some(String.prototype.includes.bind("boo"))
,或者对于some
使用可选的第二个参数thisArg:['a', 'b'].some(String.prototype.includes, "boo")
。这样可以消除错误。不过,你会注意到,some
传递的不仅是元素,还有第二个参数索引以及数组本身作为第三个参数。这是一个问题,因为includes
还接受可选的第二个参数作为开始位置。这可能会导致意外的行为,例如,数组元素"b"位于索引1处,"boo".includes("b", 1) === false
。String.prototype.includes
完全不同的函数,这样将其包装在一个新的函数中,实际上可以满足你的需求:['a', 'b'].some(e => "boo".includes(e))
,正如你已经注意到的那样。"Scott Marcus的评论是不正确的。在函数式编程中,传递没有必需参数的函数是完全正常的。下面是实际问题:
您传递给some
的回调函数被调用时会带有三个参数:currentValue
、index
和array
,它的this
将被设置为undefined
,除非您传递第二个参数给some
。方法String.prototype.includes
需要两个参数:search
和start
,它的this
作为要搜索的字符串使用。由于这种交互,includes
在没有要搜索的字符串的情况下被调用,因此会出现错误。
即使通过bind
或通过向some
传递第二个参数来修复上述问题,这仍然无法完全解决问题。问题的另一半是第二个参数。 some
认为它是index
,但includes
认为它是start
。因此,在第二个字符之前,将不会搜索b
,因此即使错误已经消失,测试仍将返回false。
在这种情况下,一个包装函数是必不可少的,以获得所需的行为。
.includes()
是一个函数,但它需要传入一个参数才能工作。而且.some()
也需要传入一个返回布尔值的函数,否则它也无法正常工作。当然,如果你只是单独传入这个函数本身的话,它也不会起作用,就好比输入"Test".replace()
一样。 - Scott Marcussome
的工作来传递该参数。你应该传递一个函数给它,而不是调用一个函数的结果。 - Joseph Sible-Reinstate Monica