NodeJS 为什么不能简化使用array.includes的回调?[duplicate]

cclgggtu  于 2023-02-03  发布在  Node.js
关注(0)|答案(4)|浏览(157)
    • 此问题在此处已有答案**:

(13个答案)
Functional use of Array.includes causes TypeError [duplicate](2个答案)
5天前关闭。
考虑以下数据:

const filters = ["c", "1"];

const data = [
  {
    name: 'a',
    values: ["a", "b", "c"],
  },
  {
    name: "b",
    values: ["a", "z", "1"],
  },
  {
    name: "c",
    values: ["z", "y", "x"],
  }
];

为了获取数据数组中值包含其中一个过滤器的所有对象,可以使用以下方法:

data.filter(entry => entry.values.some(v => filters.includes(v)));

根据我所知道的javascript规则,你可以放弃. some()调用中的anonymous/lambda函数,方法如下:

data.filter(entry => entry.values.some(filters.includes));

然而,这并不起作用,因为我们得到了错误TypeError: Cannot convert undefined or null to object。然而,做下面的工作也使它工作,但多余的,我不明白为什么有必要:

const inc = (v) => filters.includes(v);
data.filter(entry => entry.values.some(inc));

这是V8引擎中的bug(我在chrome控制台和nodejs中试过)还是我不知道的技术限制?如果是,有人能给我解释一下吗?

weylhg0b

weylhg0b1#

这里有两个问题:
1)丢失this上下文:您将includes作为someArray.includes调用,即它需要someArray作为this上下文。由于丢失了thisincludes将抛出一个错误,正如您碰巧观察到的那样。
要解决此问题,您可以执行以下操作:

const includesWithThis = [].includes.bind(filters);

2)some向下传递多个参数,例如itemindexarray等。
顺便说一下,includes接受两个参数,即itemfromIndex
所以你实际上是在调用filters.includes(value, index),其中index第一次是0,并且会随着some方法的每次迭代而递增,这会导致你的fromIndex被破坏--你总是希望它是0。
因此,这将使您的代码无论如何都会失败(即使有第一个问题的解决方案)。

filters[0] = "a"; // Something that's available after `fromIndex`
const includesWithThis = [].includes.bind(filters);
data.filter(entry => entry.values.some(includesWithThis));

不建议执行上述修复。您最好只执行原始解决方案,即:

data.filter(entry => entry.values.some(v => filters.includes(v)));
fruv7luv

fruv7luv2#

函数include丢失了数组引用(this),当你把它作为函数some的处理程序直接传递的时候。
下面的代码片段实现了一个函数fn,其中两个函数与其原型相关联。
函数handler,就像函数Array.includes,在这里我用它来打印封闭作用域的信息。

window.name = "MyWindow";
const filters = ["c", "1"];
const data = [{    name: 'a',    values: ["a", "b", "c"],  },  {    name: "b",    values: ["a", "z", "1"],  },  {    name: "c",    values: ["z", "y", "x"],  }];

function fn() {
  this.name = "myFn";
}

fn.prototype.includes = function(e) {
  return filters.includes(e);
}

fn.prototype.handler = function(e) {
  console.log(this.name); // <- Here the name will be "MyWindow" because the function lost the
                          //    enclosing scope, and now will use the enclosing scope where 
                          //    the function was calling from.
  return this.includes(e);
}

let myFn = new fn();

console.log(data.filter(entry => entry.values.some(myFn.handler/*Will use the window as enclosing scope.*/)));

现在,为了说明问题,请看下面的代码片段,看看我们是如何绑定同一个对象的,并且一切正常。

  • 这只是为了说明,别这样 *
window.name = "MyWindow";
const filters = ["c", "1"];
const data = [{    name: 'a',    values: ["a", "b", "c"],  },  {    name: "b",    values: ["a", "z", "1"],  },  {    name: "c",    values: ["z", "y", "x"],  }];

function fn() {
  this.name = "myFn";
}

fn.prototype.includes = function(e) {
  return filters.includes(e);
}

fn.prototype.handler = function(e) {
  console.log(this.name); // <- Here the name will be "myFn".
  return this.includes(e);
}

let myFn = new fn();

console.log(data.filter(entry => entry.values.some(myFn.handler.bind(myFn))));
imzjd6km

imzjd6km3#

正如注解中提到的,Array.includes方法丢失了数组引用,因此您必须执行以下操作:

const filters = [...]
// ...
const includes = filters.includes.bind(filters)

const result = data.filter(entry => entry.values.some(includes));

但是,这将无法正常工作,因为Array.includes方法的签名将valueToFind和一个可选的fromIndex作为参数:
arr.includes(valueToFind[, fromIndex])
Array.some的回调将传递elementindexarray作为参数。fromIndex参数将是当前元素的index,这将导致意外行为。
x1米11米1x

const filters = ["c", "1"];

const data = [
  {
    name: "a",
    values: ["a", "b", "c"]
  },
  {
    name: "b",
    values: ["a", "z", "1"]
  },
  {
    name: "c",
    values: ["z", "y", "x"]
  }
];

const includes = filters.includes.bind(filters);
const result = data.filter(entry => entry.values.some(includes));

console.log(result)

因此,很遗憾,您将不得不更加明确地将相关参数传递给Array.includes方法:

const filters = ["c", "1"];

const data = [
  {
    name: "a",
    values: ["a", "b", "c"]
  },
  {
    name: "b",
    values: ["a", "z", "1"]
  },
  {
    name: "c",
    values: ["z", "y", "x"]
  }
];

const includes = filters.includes.bind(filters);
const result = data.filter(entry => entry.values.some(v => includes(v)));

console.log(result)
bq3bfh9z

bq3bfh9z4#

不可以。您不能使用Array#includes,例如

data.filter(entry => entry.values.some(Array.prototype.includes, filters));
//                                     borrowed function
//                                                               thisArg

由于includes的第二个参数(用于搜索 * fromIndex *):
此数组中开始搜索 * valueToFind * 的位置。
对于正值 * fromIndex *,要搜索的第一个字符位于 * fromIndex *;对于负值 * fromIndex *,要搜索的第一个字符位于arr.length + fromIndex(使用 * fromIndex * 的absolute value作为从数组末尾开始搜索的字符数)。
默认值为0
最后,您需要直接使用该值进行检查。

const
    filters = ["c", "1"];
    data = [{ name: 'a', values: ["a", "b", "c"] }, { name: "b", values: ["a", "z", "1"] }, { name: "c", values: ["z", "y", "x"] }];

console.log(data.filter(entry => entry.values.some(v => filters.includes(v))));

相关问题