Problem
Here is a simple filter function I have:
function filter (attributes, data, include) {
if (include) {
let res = {}
if (typeof attributes === 'string') {
res[attributes] = data[attributes]
return res
}
if (attributes.length) {
attributes.forEach(attr => res[attr] = data[attr])
}
return res
} else {
if (typeof attributes === 'string') {
delete data[attributes]
return data
}
if (attributes.length) {
attributes.forEach(attr => delete data[attr])
}
return data
}
}
As you can see, these parts are same:
if (typeof attributes === 'string') {
// some code
return // some variable
}
if (attributes.length) {
attributes.forEach(attr => /* some code */)
}
return // some variable
What is the best way to remove this duplicated code?
Solution
To @Tushar’s point, those 2 code blocks are not similar. In fact, I would advise you to turn that function in to 2 functions with a better name. Especially since your function optionally depending on include
modifies data
which is not a good design. It should either always generate a new object, or always modify data
. Probably it should always generate a new object.
Furthemore for greater flexibility, I would not check for attributes.length
but for attributes.forEach
, this way you know for sure the function/method is defined.
In Lodash the first function would be called pick
, and the second function would be omit
.
Thinking about this, if you are always going to build a new object, you could remove repetitive coding:
function filter(attributes, data, include) {
'use strict';
let keys = Object.keys(data),
res = {};
//Turn attributes into an array if needed
attributes = (typeof attributes === 'string') ? [attributes] : attributes;
keys.forEach(key => {
//If its an attribute we include, get it
//If its an attribute we dont exclude, get it
if ((include && attributes.indexOf(key) != -1) ||
(!include && attributes.indexOf(key) == -1)) {
res[key] = data[key];
}
});
return res;
}