JS Hacks for Lazy Devs
Number
Rather than going to the effort of typing the Number
constructor you can just wrap a number (in parens) to access number functions…
Number(20).toFixed();
// lame!
20.toFixed();
// Error! (JS thinks this is a decimal)
(20).toFixed();
// thumbsup!
Also, the toFixed
function is a quick way to make a number look like a price…
'£' + (20).toFixed(2);
// £20.00
Filtering
Can’t bothered to check if an item is undefined? You can pass the Boolean
constructer straight into a filter call to do it for you…
['something', undefined, null, 3, 4].filter(Boolean).map(item => {
// Do whatever you like, item will never be null or undefined
});
This works because Boolean
will return false
if anything you give it is falsey. So Boolean(null)
, Boolean(undefined)
, Boolean(0)
will all return false
and get filtered out automatically.
Using join instead of the + operator
The plus sign can concat strings and even numbers but often it’s tricky to use if you’re not sure your values are defined or undefined:
let fullName = '';
// Rubbish, the fullName could show as "undefined Smith"
if (user.firstName || user.lastName) {
fullName = user.firstName + ' ' + user.lastName;
}
// Also rubbish, fullName could be " Smith"
if (user.firstName || user.lastName) {
fullName =
(user.firstName ? user.firstName : '') + ' ' + (user.lastName ? user.lastName : '');
}
// This works but...seriously? Rubbish
if (user.firstName || user.lastName) {
fullName =
(user.firstName ? user.firstName : '')
+ (user.lastName ? (' ' + user.lastName) : '');
}
Instead, use the filter
trick with a join
:
const fullName = [user.firstName, user.lastName]
.filter(Boolean)
.join(' ');
Using Includes the wrong way around
You often want to find if a string matches a set of values rather than just one:
if (
myString === 'case1'
|| myString === 'case2'
|| myString === 'case3'
) {
// Do stuff...
}
Rather than writing all these or conditions why not just invert an includes
function to do it for you:
if (['case1', 'case2', 'case3'].includes(myString)) {
// Do stuff...
}
Ternary checks
Using an old version of Node without optional chaining but don’t want to waste time using extra if
statements?
With optional chaining you’d just do this…
const propertyThatMightExist = myObject?.propertyThatMightExist;
Here’s the old school hack with better support…
const propertyThatMightExist = (myObject || {}).propertyThatMightExist;
You can also set a default with this method…
const propertyThatMightExist =
(myObject || { propertyThatMightExist: 'cool' }).propertyThatMightExist;
Conditional properties
Want to add a property but only if it’s defined? Sometimes you don’t know if a value is defined and you don’t want to add the valued undefined
if it’s not…
const myObj = {
value: myValueThatMightBeUndefined,
};
If myValueThatMightBeUndefined
is undefined I don’t want the property value
at all, so I might do something like this…
let myObj = {};
if (myValueThatMightBeUndefined) {
myObj.value = myValueThatMightBeUndefined;
}
But you can do this using a spread inside parens…
const myObject = {
...(myValueThatMightBeUndefined
? { value: myValueThatMightBeUndefined }
: {}
),
};
You can also do this using Object.assign
…
const myObject =
Object.assign(
{},
propertyThatMightExist && { value: myValueThatMightBeUndefined }
);
Higher Order Loops
Ever wanted to make a loop from a number but didn’t want other devs to think you’re a newb for using a for
?
Try Array().fill()
:
Array(9).fill().map(() => {
// Loops 9 times...
});
Doing Array(9)
makes an array with a length of 9, weirdly though it doesn’t fill the array with anything. So to make it useable you call fill
afterwards.
Awaits with thens
This is sort of sacrilege but I often use then
and catch
in combination with an await
because it allows me to handle errors without a try/catch
block effecting the scope.
Here’s what I used to do:
let results;
try {
const { data } = await axios('/data');
results = data;
} catch (error) {
// I might want to ignore the error...
results = [];
}
I hate declaring the variable first, but I often have to because I won’t be able to use it outside the try
block otherwise.
Here’s a much cleaner way of doing the same thing:
const results = await axios('/data')
.then(res => res?.data || [])
.catch(() => []);
I’ve basically reverted back to using the normal promise API here but the await
lets me escape the functional style and keep things clear and linear.
This is also handy if you’re getting records but only want, say, the ids…
const userIds = await User.find()
.then(users => users?.map(u => u._id) || []);