简体   繁体   English

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

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

A function should do only one thing is considered a good practice when writing functions.一个 function 应该只做一件事被认为是编写函数时的一个好习惯。 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.但是,我有一个已经非常小的 function,但我认为它可以进一步提取,但我不知道如何做到这一点。

The following recode() function replaces array values according to a look-up dictionary.以下recode() function 根据查找字典替换数组值。

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:在我看来,当前的recode() function 做了两件事:

  1. It matches by identity (you might have a better description than this), ie, elem => dict[elem] ;它按身份匹配(您可能有比这更好的描述),即elem => dict[elem] and
  2. it maps over arr它映射到arr

My question is whether I can extract an individual function for elem => dict[elem] , and supply that function to arr.map() .我的问题是我是否可以为elem => dict[elem]提取个人 function ,并将该 function 提供给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 .这样,我将有一个 function 只做替换,另一个只映射arr


EDIT编辑


To address the comments, I would like to make an analogy.针对评论,我想打个比方。 Let's consider a function that doubles array values.让我们考虑一个将数组值加倍的 function。

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

Some folks here might say that doubleArray() is already doing one thing.这里有些人可能会说doubleArray()已经在做一件事了。 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).据我所知, doubleArray()做了两件事(double 和 map),而doubleArray2()只做了一件事(map)而doubleNumber()做了一件事(double)。 Therefore, doubleArray() is not a meaningless refactoring.因此, doubleArray()并不是无意义的重构。

Furthermore, once we have a function that does one thing, it promotes more accurate unit tests we can write for it.此外,一旦我们有一个 function 做一件事,它就会促进我们可以为它编写更准确的单元测试。

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() .最后,如果我们将这段代码翻译成typescript (我在这个问题中没有重点关注),那么doubleNumber()中的输入类型与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.我对 javascript 很陌生,但这是我的理解方式。 So my question about recode() was within this context.所以我关于recode()的问题是在这种情况下。

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.你的选择。

In essence recode is being used a wrapper around arr.map() .本质上, recode被用作arr.map()的包装器。 This could also be achieved by assigning recode to a function returned by calling the Function.bind() method .这也可以通过将recode分配给调用Function.bind()方法返回的 function 来实现。

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

But perhaps it is simpler just to call .map() directly:但也许直接调用.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]

If there is a desire to have a user-supplied callback, then the ES-6 default parameters could be used:如果希望有一个用户提供的回调,那么可以使用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"]

A slight variation on Daniel's answer : Have the other function return a function that can be used as callback for Array#map : Daniel 的回答略有不同:让另一个 function 返回一个 function 可以用作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.但我也会质疑这是否真的是对您原始代码的改进。

You do not need to extract in your case, thats why arrow functions exist.你不需要在你的情况下提取,这就是箭头函数存在的原因。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM