重写 _.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
。但是我已经在这里过了头,所以... ;-)
我正在尝试从头开始重写 _.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
。但是我已经在这里过了头,所以... ;-)