如何从 arr.map(elem => dict[elem]) 中提取函数?

How to extract a function out of arr.map(elem => dict[elem])?

一个函数应该只做一件事 被认为是编写函数时的一个好习惯。然而,我有一个已经非常小的功能,但是我认为它可以进一步提取,但我不知道如何做到这一点。

以下 recode() 函数根据查找字典替换数组值。

function recode(arr, dict) {
    return arr.map(elem => dict[elem])
}

工作原理示例:

// input data to be recoded
const myArr = ['eggplant', 'tomato', 'carrot', 'cabbage'];

// look-up dictionary
const myDict = {
    eggplant: 'purple',
    tomato: 'red',
    carrot: 'orange',
};

const result1 = recode(myArr, myDict)
console.log(result1) // => ["purple", "red", "orange", undefined]

在我看来,当前的 recode() 函数做了两件事:

  1. 它按身份匹配(您可能有比这更好的描述),即elem => dict[elem];和
  2. 它映射到 arr

我的问题是我是否可以为 elem => dict[elem] 提取一个单独的函数,并将该函数提供给 arr.map()。我想象的是:

// pseudo-code
function funcInner() {...}

function recode(arr, dict) {
    return arr.map(funcInner)
}

这样,我将拥有一个仅执行替换的功能,而另一个仅映射 arr


编辑


针对评论,我想打个比方。让我们考虑一个将数组值加倍的函数。

function doubleArray(arr) {
  return arr.map(x => x * 2)
}

这里有些人可能会说 doubleArray() 已经在做一件事了。但是,我们仍然可以提取:

const doubleNumber = x => x * 2;

function doubleArray2(arr) {
  return arr.map(doubleNumber)
}

据我了解,doubleArray() 做了两件事(double & map),而 doubleArray2() 只做了一件事(map)而 doubleNumber() 做了一件事(doubles) .因此,doubleArray()并不是无意义的重构。

此外,一旦我们有了一个只做一件事的函数,它就会促进我们可以为它编写更准确的单元测试。

最后,如果我们将这段代码翻译成 typescript(我在这个问题中没有关注),那么 doubleNumber() 中的输入类型与doubleArray() 中的输入类型。所以这是我更喜欢提取的另一个原因。

我是 javascript 的新手,但这是我的理解方式。所以我关于 recode() 的问题就是在这种情况下。

在你的情况下你不需要提取,这就是箭头函数存在的原因。

回答你的问题:

function recode(arr, dict) {
    return arr.map(elem => funcInner(elem,dict));
};

function funcInner(elem, dict) {
    return dict[elem];
}

但我同意其他人对你问题的评论,这可能有点矫枉过正。您的选择。

本质上 recode 被用作 arr.map(). This could also be achieved by assigning recode to a function returned by calling the Function.bind() method 的包装器。

const recode = myArr.map.bind(myArr, elem => myDict[elem]);

myArr需要作为第一个参数传入,绑定数组上下文

// input data to be recoded
const myArr = ['eggplant', 'tomato', 'carrot', 'cabbage'];

// look-up dictionary
const myDict = {
    eggplant: 'purple',
    tomato: 'red',
    carrot: 'orange',
};
const recode = myArr.map.bind(myArr, elem => myDict[elem]);
const result1 = recode(myArr, myDict)
console.log(result1) // => ["purple", "red", "orange", undefined]

但也许直接调用 .map() 更简单:

// input data to be recoded
const myArr = ['eggplant', 'tomato', 'carrot', 'cabbage'];

// look-up dictionary
const myDict = {
    eggplant: 'purple',
    tomato: 'red',
    carrot: 'orange',
};
const result1 = myArr.map(elem => myDict[elem])
console.log(result1) // => ["purple", "red", "orange", undefined]

如果希望有一个user-supplied回调,那么可以使用ES-6 default parameters

function recode(myArr, myDict, callback = elem => myDict[elem]) {
  return myArr.map(callback);
}
// input data to be recoded
const myArr = ['eggplant', 'tomato', 'carrot', 'cabbage'];

// look-up dictionary
const myDict = {
  eggplant: 'purple',
  tomato: 'red',
  carrot: 'orange',
};

const result1 = recode(myArr, myDict)
console.log(result1) // => ["purple", "red", "orange", undefined]

const result2 = recode(myArr, myDict, elem => myDict[elem] + 'a')
console.log(result2) // => ["purplea", "reda", "orangea", "undefineda"]

的细微变化:让另一个函数 return 可以用作 Array#map 的回调函数:

function createMapper(dict) {
  return elem => dict[elem];
}

function recode(arr, dict) {
    return arr.map(createMapper(dict));
}

但我也会质疑这是否真的是对您原始代码的改进。