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

发布于 2025-01-11 15:50:45 字数 1919 浏览 0 评论 0原文

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

以下 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 =>字典[元素];它
  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() 只做一件事(双精度)。因此,doubleArray()并不是无意义的重构。

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

最后,如果我们将此代码转换为 typescript (我在这个问题中没有重点关注),那么 doubleNumber() 中的输入类型与输入类型不同在 doubleArray() 中。这就是我更愿意提取的另一个原因。

我对 javascript 很陌生,但这就是我理解它的方式。所以我关于 recode() 的问题就是在这种情况下发生的。

A function should do only one thing is considered a good practice when writing functions. However, I have a function that is already very minimal, but nevertheless I think it can be further extracted, but I don't know how this can be done.

The following recode() function replaces array values according to a look-up dictionary.

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

Example to how it works:

// 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]

The way I see it, the current recode() function does two things:

  1. It matches by identity (you might have a better description than this), i.e., elem => dict[elem]; and
  2. it maps over arr

My question is whether I can extract an individual function for elem => dict[elem], and supply that function to arr.map(). I imagine something along the lines of:

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

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

This way, I will have one function that does only the replacement, and another that only maps over arr.


EDIT


To address the comments, I would like to make an analogy. Let's consider a function that doubles array values.

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

Some folks here might say that doubleArray() is already doing one thing. However, we could still extract:

const doubleNumber = x => x * 2;

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

As far as I understand, doubleArray() did two things (double & map), whereas doubleArray2() does only one thing (map) and doubleNumber() does one thing (doubles). Therefore, doubleArray() is not a meaningless refactoring.

Furthermore, once we have a function that does one thing, it promotes more accurate unit tests we can write for it.

Lastly, if we translated this code to typescript (which I didn't focus on in this question), then the input type in doubleNumber() is different than the input type in doubleArray(). So that's another reason why I would prefer to extract.

I'm very new to javascript, but this is the way I understand it. So my question about recode() was within this context.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

夏末 2025-01-18 15:50:45

回答你的问题:

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

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

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

To answer your question:

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

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

But i agree with the others commenting on you question, this may be a little overkill. Your choice.

假情假意假温柔 2025-01-18 15:50:45

本质上,recode 被用作 arr.map()。这也可以通过将 recode 分配给调用 Function.bind() 方法

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]

如果需要用户提供的回调,则 可以使用 ES-6 默认参数

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"]

In essence recode is being used a wrapper around 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 needs to be passed as the first parameter to bind the context of the array.

// 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]

But perhaps it is simpler just to call .map() directly:

// 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]

If there is a desire to have a user-supplied callback, then the ES-6 default parameters could be used:

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"]

信愁 2025-01-18 15:50:45

Daniel 的回答略有不同:让另一个函数返回一个可用作 Array# 回调的函数map:

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

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

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

A slight variation on Daniel's answer: Have the other function return a function that can be used as callback for Array#map:

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

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

But I would also question whether this is really an improvement over your original code.

祁梦 2025-01-18 15:50:45

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

You do not need to extract in your case, thats why arrow functions exist.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文