重写 _.invoke

Rewrite _.invoke

我正在尝试从头开始重写 _.invoke 函数,但只成功了一半。我的函数应该采用一个集合、一个 methodName 和可选的附加参数以及 return 一个数组,其中包含对集合中的每个值调用 methodName 指示的方法的结果。传递给 invoke 的任何额外参数都将转发给方法调用。

这是我的代码:

_.invoke = function (collection, methodName) {
  let res = [];
  if (Array.isArray(collection)) {
    for (let i = 0; i < collection.length; i++) {
      res.push(collection[i][methodName](arguments));
    }
  } else {
    for (const [key, value] of Object.entries(collection)) {
      res.push(value[methodName](arguments));
    }
  }
  return res;
};

由于未正确传递参数,目前正在失败。谁能给我任何意见或建议,为什么会发生这种情况?

你传递的是 arguments 伪数组而不是它的内容,你传递的是 整个 东西,但你可能不想传递方法名称的集合。

相反,在函数签名上使用剩余参数,然后在调用方法时将其展开:

_.invoke = function (collection, methodName, ...args) {
//                                         ^^^^^^^^^−−−−−−− rest param
  let res = [];
  if (Array.isArray(collection)) {
    for (let i = 0; i < collection.length; i++) {
      res.push(collection[i][methodName](...args));
//                                       ^^^−−−−−−−−−−−−−−− spread notation
    }
  } else {
    for (const [key, value] of Object.entries(collection)) {
      res.push(value[methodName](...args));
//                               ^^^−−−−−−−−−−−−−−−−−−−−−−− spread notation
    }
  }
  return res;
};

旁注:您可能希望允许 any 可迭代,而不仅仅是一个数组,您可以使用 Object.values 来获取对象值的数组。

_.invoke = function (collection, methodName, ...args) {
    const iterable = isIterable(collection) ? collection : Object.values(collection);
    const res = Array.from(iterable).map(entry => entry[methodName](...args));
    return res;
};

...其中 isIterable 是:

function isIterable(obj) {
    return obj && typeof obj[Symbol.iterator] === "function";
}

或者,如果对数组进行不必要的浅表复制让您感到困扰:

_.invoke = function (collection, methodName, ...args) {
    const array = Array.isArray(collection)
        ? collection
        :  isIterable(collection) ? Array.from(collection) : Object.values(collection);
    const res = array.map(entry => entry[methodName](...args));
    return res;
};

如果您需要在 collection 上重复执行这三个步骤,您可以使用辅助函数:

function arrayForAny(x) {
    const array = Array.isArray(x) ? x :  isIterable(x) ? Array.from(x) : Object.values(x);
}

您还可以检查类数组并将其传递给 Array.from 而不是对它们使用 Object.values。但是我已经在这里过了头,所以... ;-)