将“Array.prototype.includes”传递给回调而不将其包装在匿名函数中?

Pass `Array.prototype.includes` to callback without wrapping it in an anonomous function?

为什么我需要将 animals.includes 包装在一个匿名函数中才能使以下 ES6 js 代码按预期工作?

const animals = ["ape", "dog", "pig"]
const nouns = ["car", "planet", "apple", "dog"]

const hasPulse = nouns.some((n) => animals.includes(n))

console.log(`Heartbeat ${hasPulse ? '' : 'not '}detected!`)

如果我打开 animals.includes 它会抛出类型错误。

// this fails with TypeError: can't convert undefined to object
const hasPulse = nouns.some(animals.includes)

some() 方法测试数组中的一个或多个元素是否通过了提供的函数中实现的测试,returns 一个指示结果的布尔值。

const hasPulse = nouns.some((n) => animals.includes(n))

第二个选择行不通。 Array.includes 使用从调用函数接收的第二个参数 (fromIndex) 作为索引并省略该函数要检查的值。

我认为这是一个上下文问题,您应该将 includes 函数绑定到 nouns 数组,以便它按照您希望的方式工作。您拥有的代码无法按预期工作的原因是,当您将 includes 函数传递给 some 时,它​​不会在数组上执行(这要么未定义,要么设置为 window 中的对象浏览器)。这是工作示例

const animals = ["ape", "dog", "pig"]
const nouns = ["car", "planet", "apple", "dog"]

const hasPulse = nouns.some(animals.includes.bind(nouns))

console.log(`Heartbeat ${hasPulse ? '' : 'not '}detected!`)

你可以

const hasPulse = nouns.some(Array.prototype.includes, animals);

thisArgs,但不幸的是Array#includes具有第二个参数fromIndex,它由索引移交并破坏了想要的结果。

它与 Javascript 方法如何“知道”它在调用时附加到哪个对象有关:它的 this 引用。

includes 可能会像这样实现(假设示例):

Array.prototype.includes = function includes(couldBeMember) {
  for (const member of this) {
    if (member === couldBeMember) {
      return true;
    }
  }
  return false;
}

animals.includes(argument)argument 传递给 Array.prototype.includes,但也在调用期间将其 this 设置为 animals。仅引用 animals.includes 并将其传递到其他地方,与传递 Array.prototype.includes 没有什么不同;如果它最终被调用(在 some 内)而不引用 animals,它不会将 animals 设置为它的 this.

要创建一个“记住”它的 thisanimals 的函数 includes,无论函数本身传递到哪里,您都必须 bind 它至 animalsanimals.includes.bind(animals)(或 Array.prototype.includes.bind(animals)[].includes.bind(animals))。

const animals = ["ape", "dog", "pig"]
const nouns = ["car", "planet", "apple", "dog"]

const hasPulse = nouns.some([].includes.bind(animals))

这并不比仅使用 lambda 干净很多,但希望能回答您的问题。

如果您喜欢这个想法但想清理它,您可以创建一个独立的 bind 来做这样的事情:

function bind(self, method, ...args) {
  return self[method].bind(self, ...args);
}

const hasPulse = nouns.some(bind(animals, "includes"))

(还有至少一个建议创建一个执行等效绑定的运算符,类似于 animals::includes,但我不认为它已经完成,但我最后检查过所以语法可能会改变或它可能不会最终得到支持。)

这是因为 Array.prototype.some() 调用回调的方式与 Array.prototype.includes() 期望参数的方式不兼容。

[].includes()的完整定义是:

[].includes(thingToSearch, startSearchFrom);

例如,如果您这样做:

[1,2,3,4,5].includes(1,3); // false

它会 return false 即使数组明确包含 1。这是因为你告诉它从元素 3 开始搜索,所以 .includes() 只查看了 45 而找不到 1.

[].some()的完整定义是:

[].some(function (item, index, theArray) {}, this);

因此 .some() 会将当前项目的索引传递给您传递给它的回调。例如,如果您这样做:

[10,20,30,40,50].some((x,y) => y == 2); // 30

它会 return 30 因为他第一次 .some() 遍历它传递给 10x0 的数组y。第二次它通过 20x1y。第三次 y 将是 2 所以 y == 2 是真的所以它 return 是 true 的值,即 30

现在您可以看到 .some() 作为第二个参数传递的内容和 .includes() 期望作为第二个参数的内容具有不同的含义。

.some() 方法将传递循环索引,而 .includes() 方法期望第二个参数告诉它从哪里开始搜索。

所以如果你这样做:

const animals = ["ape", "dog", "pig"];
const nouns = ["car", "planet", "apple", "dog"];

nouns.some(animals.includes);
  1. .. 它会在 ape,dog,pig,

    中搜索 car
  2. .. 然后它会在 dog,pig 中搜索 planet (记住索引现在是 1 所以你告诉 .includes() 忽略 ape )

  3. .. 然后它会在 pig 中搜索 apple (索引现在是 2 所以 .includes() 忽略 apedog)

  4. .. 然后它会在一个空数组中搜索 dog,当然它不会找到。

当然,可能有一些您想要执行此操作的算法。但我不认为这是你期望发生的事情。