简体   繁体   English

将 `Array.prototype.includes` 传递给回调而不将其包装在异常的 function 中?

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

Why do I need to wrap animals.includes in an anonymous function for the following ES6 js code to work as expected?为什么我需要将animals.includes包装在匿名 function 中,以使以下 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!`)

If I unwrap animals.includes it throws a type error.如果我打开animals.includes,它会抛出一个类型错误。

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

You could not take不能接受

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

with thisArgs , but unfortunately Array#includes features a second parameter fromIndex , which is handed over by the index and destroys the wanted result.使用thisArgs ,但不幸的是Array#includes具有第二个参数fromIndex ,该参数由索引传递并破坏了想要的结果。

I believe this is a context issue, you should bind the includes function to the nouns array for it to work the way you want it to.我相信这是一个上下文问题,您应该将包含 function 绑定到名词数组,以便它按照您希望的方式工作。 The reason why the code you have is not working as you expect it is because when you pass the includes function to the some, it is not executed on the array (this is either undefined or is set to the window object in the browser).您拥有的代码无法按预期工作的原因是,当您将包含 function 传递给某些时,它不会在数组上执行(这要么未定义,要么设置为 window ZA8CFDE6331BD49EB2AC96F891 中的 Z05B8C74CBD96FBF4Z ZA8CFDE6331BD59EB2AC96F891)。 Here is the working example这是工作示例

 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!`)

It has to do with how a Javascript method "knows" which object it was attached to when called: its this reference.它与 Javascript 方法如何“知道”它在调用时附加到哪个 object 有关:它的this参考。

includes might be implemented something like this (hypothetical example): includes可能会像这样实现(假设示例):

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

animals.includes(argument) passes argument to Array.prototype.includes , but also sets its this to animals during the call. animals.includes(argument)argument传递给Array.prototype.includes ,但在调用期间也将this设置为animals Just referencing animals.includes and passing that elsewhere, is no different than passing Array.prototype.includes ;只是引用animals.includes并将其传递到其他地方,与传递Array.prototype.includes没有什么不同; if it is ultimately called (inside some ) without reference to animals , it won't get animals set as its this .如果它最终被调用(在some内部)而不参考animals animals为它的this

To create a function includes that "remembers" its this is animals , no matter where the function by itself is passed, you have to bind it to animals : animals.includes.bind(animals) (or Array.prototype.includes.bind(animals) or [].includes.bind(animals) ).要创建一个 function includes “记住”它的this is animals ,无论 function 本身在哪里传递,您都必须将它绑定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))

This isn't a whole lot cleaner than just using a lambda, but hopefully answers your question.这并不比仅使用 lambda 更干净,但希望能回答您的问题。

If you like the idea but want to clean it up, you could create a freestanding bind that does something like so:如果您喜欢这个想法但又想清理它,您可以创建一个独立的bind ,执行如下操作:

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

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

(There's also at least one proposal out there to create an operator that performs the equivalent binding, something like animals::includes , but I don't believe that's finalized yet last I checked so the syntax might change or it might not end up supported.) (至少还有一个提议来创建一个执行等效绑定的运算符,例如animals::includes ,但我不相信这已经完成,但我最后检查了一下,所以语法可能会改变,或者它可能最终不受支持.)

It's because of the incompatibility between how Array.prototype.some() calls it's callback and how Array.prototype.includes() expect arguments.这是因为Array.prototype.some()如何调用它的回调与Array.prototype.includes()如何期望 arguments 之间不兼容。

The full definition of [].includes() is: [].includes()的完整定义是:

[].includes(thingToSearch, startSearchFrom);

For example, if you do:例如,如果您这样做:

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

It would return false even though the array clearly includes 1 .即使数组清楚地包含1 ,它也会返回false This is because you told it to start searching from element 3 so .includes() only looked at 4 and 5 and could not find 1 .这是因为您告诉它从元素3开始搜索,所以.includes()只查看了45并且找不到1

The full definition of [].some() is: [].some()的完整定义是:

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

So the .some() will pass the index of the current item to the callback you pass to it.因此.some()会将当前项目的索引传递给您传递给它的回调。 For example if you do:例如,如果您这样做:

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

It would return 30 because he first time .some() loops over the array it passes 10 to x and 0 to y .它将返回30 ,因为他第一次.some()循环遍历数组,它将10传递给x并将0传递给y The second time it passes 20 to x and 1 to y .第二次将20传递给x并将1传递给y And the third time y will be 2 so y == 2 is true so it returns the value where it is true which is 30 .第三次y将为2 ,因此y == 2为真,因此它返回为true值,即30

Now you can see that what .some() passes as the second argument and what .includes() expects as the second argument have different meanings.现在您可以看到.some()作为第二个参数传递的内容和.includes()期望作为第二个参数传递的内容具有不同的含义。

The .some() method will pass the loop index while the .includes() method expect the second argument to tell it where to start searching. .some()方法将传递循环索引,而.includes()方法期望第二个参数告诉它从哪里开始搜索。

So if you do:所以如果你这样做:

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

nouns.some(animals.includes);
  1. .. it would search for car in ape,dog,pig , ..它会在ape,dog,pig中搜索car

  2. .. then it would search for planet in dog,pig (remember index is now 1 so you are telling .includes() to ignore ape ) .. 然后它会在dog,pig中搜索planet (记住 index 现在是 1 所以你告诉.includes()忽略ape

  3. .. then it would search for apple in pig (index is now 2 so .includes() ignores ape and dog ) .. 然后它会在pig中搜索apple (索引现在是 2 所以.includes()忽略了apedog

  4. .. then it would search for dog in an empty array which of course it would not find. ..然后它会在一个空数组中搜索dog ,当然它不会找到。

Sure, there may be some algorithm where you want to do this.当然,可能有一些算法你想这样做。 But I don't think this is what you expect to happen.但我不认为这是你期望发生的。

The some() method tests if one element or more in the array passes the test implemented in the provided function and returns a Boolean value indicating the result. some() 方法测试数组中的一个或多个元素是否通过了在提供的 function 中实现的测试,并返回指示结果的 Boolean 值。

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

The second alternative won't work.第二种选择行不通。 Array.includes uses a second parameter (fromIndex) which is received from the calling function as index and omits values to be checked by that function. Array.includes 使用从调用 function 接收的第二个参数 (fromIndex) 作为索引,并省略要由该 function 检查的值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM