17 lines of JS code became 1 line after this simple trick
How did these 17 lines of JavaScript code turn into a one-liner function?
It's easy, you'll see!
The 1st thing we notice is we're selecting items from an array - this should NEVER take 3 lines in JavaScript!
We have the destructuring operator to turn this:
function extractRedirects(str) {
const lines = str.split('\n');
const sourceDestinationList = [];
for (const line of lines) {
const sourceDestination = line.split(' ');
const source = sourceDestination[2];
const destination = sourceDestination[3];
const redirectObj = {
source: source,
destination: destination,
permanent: true,
};
sourceDestinationList.push(redirectObj);
}
return sourceDestinationList;
}
into this:
function extractRedirects(str) {
const lines = str.split('\n');
const sourceDestinationList = [];
for (const line of lines) {
// ✅ Skip 1st two with comma placeholders!
const [, , source, destination] = line.split(' ');
const redirectObj = {
source: source,
destination: destination,
permanent: true,
};
sourceDestinationList.push(redirectObj);
}
return sourceDestinationList;
}
What else is obvious? A loop and a gradual accumulation (with push
).
Which means we're easily cutting out statements here with map()
or reduce()
:
reduce
works well anywhere but map
is the natural choice since 1 array clearly transforms to another here.
So we go from this:
function extractRedirects(str) {
const lines = str.split('\n');
const sourceDestinationList = [];
for (const line of lines) {
const [, , source, destination] = line.split(' ');
const redirectObj = {
source: source,
destination: destination,
permanent: true,
};
sourceDestinationList.push(redirectObj);
}
return sourceDestinationList;
}
To this:
function extractRedirects(str) {
const lines = str.split('\n');
const sourceDestinationList = lines.map((line) => { // ✅
const [, , source, destination] = line.split(' ');
const redirectObj = {
source: source,
destination: destination,
permanent: true,
};
// ✅
return redirectObj;
});
return sourceDestinationList;
}
The declaration, for loop and push()
have all been eradicated.
Now removing the temporary variable:
function extractRedirects(str) {
const lines = str.split('\n');
const sourceDestinationList = lines.map((line) => {
const [, , source, destination] = line.split(' ');
return {
source: source,
destination: destination,
permanent: true,
};
});
return sourceDestinationList;
}
And combining the last 2 statements in map
's callback - without calling split()
twice.
function extractRedirects(str) {
const lines = str.split('\n');
const sourceDestinationList = lines.map((line) => {
return line.split(' ').reduce(
(acc, curr, i) => {
return i === 2
? { ...acc, source: curr }
: i === 3
? { ...acc, destination: curr }
: acc;
},
{ permanent: true }
);
});
return sourceDestinationList;
}
reduce()
has a way of making your head spin!
Let's go with this instead; much more readable:
function extractRedirects(str) {
const lines = str.split('\n');
const sourceDestinationList = lines
.map((line) => {
return line.split(' ');
})
.map(([, , source, destination]) => {
return {
source: source,
destination: destination,
permanent: true,
};
});
return sourceDestinationList;
}
Now we can remove the callback braces, from (a) => { return { b; } }
to (a) => ({ b })
:
function extractRedirects(str) {
const lines = str.split('\n');
const sourceDestinationList = lines
.map((line) => line.split(' '))
.map(([, , source, destination]) => ({
source: source,
destination: destination,
permanent: true,
}));
return sourceDestinationList;
}
All that's left now is to remove the 2 remaining temp vars and use implicit property values:
function extractRedirects(str) {
return str
.split('\n')
.map((line) => line.split(' '))
.map(([, , source, destination]) => ({
source, // ✅
destination, // ✅
permanent: true,
}));
}
Arrow function:
const extractRedirects = (str) =>
str
.split('\n')
.map((line) => line.split(' '))
.map(([, , source, destination]) => ({
source,
destination,
permanent: true,
}));
Yes refactors are fun; it's fun to see the function gradually evolve and grow in a compact one-liner form.
And it wasn't just for fancy; With it I moved a GIGANTIC amount of redirect information...
From painful, dinosaur WP Apache .htaccess
:
To lovely, modern next.config.js
And it worked perfectly.
See also
- This tiny mistake completely ruins your code
- This is how functional try-catch transforms your JavaScript code
- Shuffling algorithm in 1 line instead of 10: functional Fisher-Yates
- This new JavaScript operator is an absolute game changer
- Stop using double negatives or nobody will understand your code
- Stop writing code comments