使用高阶函数的字符串方法

13

在尝试使用高阶函数与字符串方法时,我遇到了一个奇怪的问题。这会抛出一个错误:

['a', 'b'].some('boo'.includes)

为了使它起作用,我必须将谓词包装在另一个函数中。但是'boo'.includes不已经是一个函数吗?

这适用于普通函数:

const boo = {
    includes: () => true
};

['a', 'b'].some(boo.includes)

有没有一些特殊的字符串方法属性阻止它们像这样被组合?


4
.includes() 是一个函数,但它需要传入一个参数才能工作。而且.some()也需要传入一个返回布尔值的函数,否则它也无法正常工作。当然,如果你只是单独传入这个函数本身的话,它也不会起作用,就好比输入 "Test".replace() 一样。 - Scott Marcus
5
“some”函数的第一个参数是一个带有一个参数的函数,对吗?这里我传递给它一个带有一个参数并返回布尔值的函数,但我不太明白为什么它不起作用。 - sliptype
1
@ScottMarcus,那完全是错误的,与问题无关。我和ASDFGerte的回答都解释了实际的问题。 - Joseph Sible-Reinstate Monica
2
@ScottMarcus 这是some的工作来传递该参数。你应该传递一个函数给它,而不是调用一个函数的结果。 - Joseph Sible-Reinstate Monica
4
我觉得奇怪的是,Scott在错误的情况下没有得到任何更正就获得了3个点赞。这让我感到相当困惑了一段时间。 - Slava Knyazev
显示剩余5条评论
2个回答

16
""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)),正如你已经注意到的那样。"

1
谢谢,这真的很有启发性,我很感激您清晰地解释了上下文丢失的原因。 - Bashu Naimi-Roy

3

Scott Marcus的评论是不正确的。在函数式编程中,传递没有必需参数的函数是完全正常的。下面是实际问题:

您传递给some的回调函数被调用时会带有三个参数:currentValueindexarray,它的this将被设置为undefined,除非您传递第二个参数给some。方法String.prototype.includes需要两个参数:searchstart,它的this作为要搜索的字符串使用。由于这种交互,includes在没有要搜索的字符串的情况下被调用,因此会出现错误。

即使通过bind或通过向some传递第二个参数来修复上述问题,这仍然无法完全解决问题。问题的另一半是第二个参数。 some认为它是index,但includes认为它是start。因此,在第二个字符之前,将不会搜索b,因此即使错误已经消失,测试仍将返回false。

在这种情况下,一个包装函数是必不可少的,以获得所需的行为。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接