Skip to content
loading...

9 Extremely Powerful JavaScript Hacks

Klaus on December 09, 2019

I like to optimize. But users don't care about my optimized code if the site isn't working in their Internet Explorer 11 browser. I use Endtest t... [Read Full]
markdown guide
 

Hi, good article.

I just wanted to point out, that there is a native way of flattening multidimensional arrays (and also faster).

var flat_entries = entries.flat(); 

It also allows you to specify depth of flattening.

 
 

I noticed the same thing... adding

entries.flat(Infinity)

will flatten the array down to a single array no matter how nested the array is :)
Oh... and also, super-helpful Post!

 

Interesting. Thank you for pointing that out.

 
 

Polyfills exist.
We cannot be stuck in the past so just we support all browsers (+ solutions in the article use spreading, which isn't supported by IE anyway)

i.e. has to add an extra babel plugin on the pipeline

 

I wanted to point out that #9 (using length to empty an array) is particularly useful if you are using ES6+ syntax and declaring your arrays with const instead of var. This keeps you from having to declare your array with let just to empty it.

I also wanted to share that according to tests I ran using several benchmarking tools, it is slightly faster on some browsers to convert a string to a number by multiplying it by 1 then by using the + operator as you do in #4:

const stringNum = "256.3"
const number = stringNum * 1;
console.log(number); // Logs 256.3

The difference is pretty negligible though. The fastest three methods were all very close in speed. Your method, the above method of multiplying by 1, and in a close third is using the Number constructor:

const number = Number(stringNum);

Here are another couple of quick things I've picked up.

A more performant and shorter replacement for Math.trunc(num) and parseInt(num), as well as working as a replacement for Math.floor(num) if you know the number won't be negative, using bitwise operator. This works on numbers stored as strings as well as regular numbers:

const num = 568.328;
const strNum = "243.782";

const truncatedNum1 = num|0;
const truncatedNum2 = strNum|0;

console.log(truncatedNum1); // Logs 568
console.log(truncatedNum2); // Logs 243

A more performant, albeit limited, way to fix a number to a single decimal place rather than use the incredibly slow num.toFixed(1):

const fixToOne = num =>
  (num = Math.round(num * 10) / 10) + (num === (num|0) ? '.0' : '');

fixToOne(2.3892); // Returns "2.4"

You can change the function by wrapping the returned value in parens and multiply by 1 at the end if you need a number returned rather than a string, but toFixed() returns a string so that's what I decided to return too.

A more performant but limited way to fix a number to two decimal places rather than use the incredibly slow num.toFixed(2):

const fixToTwo = num => 
  (num = (Math.round(num * 100) / 100) +
  (num === (num|0) ? '.0' : 0)) + (num === (num|0) ? '.0' : '') +
  (num * 10 === ((num * 10)|0) ? '0' : '');

fixToTwo(2.3892); // Returns "2.39"

You can see the benchmarks on these custom functions versus the native toFixed() and witness how drastic the speed difference is here: jsperf.com/decimal-rounding-tofixe...

 

"You can change the function by wrapping the returned value in parens and multiply by 1 at the end if you need a number returned rather than a string"

But the function already has a part that freshly generates the raw rounded number: Math.round(num * 10) / 10. Just leaving that part will do; no need to generate a number -> cast to string -> cast to number

 

That's really interesting.
Thank you for sharing that information with us.
I appreciate it.

 

No problem. I added it to above post in an edit after your reply, but in case you didn't see it and are interested, you can check out my benchmarks for the custom toFixed functions here:

jsperf.com/decimal-rounding-tofixe...

It is DRASTICALLY faster as toFixed is painfully slow. Usually this wouldn't matter, but I had a usecase where I had an animation function that was getting called dozens of times a second and there were 3 places in it that required fixing a value to a set number of decimal places. Animation was noticeably smoother when I replaced toFixed with my custom functions.

 

bitwise operator

Do note that limits the returns to 32-bit and will lose data on larger decimals/integers.

 

As a JS developer working in a team I would not do 7/9 things on this list to a colleague. Even more so I wouldn't do them to myself. Keeping things clear should be every developer's objective, otherwise we may as well write everything on one line and call it a day.

 

I'm having my first ride as a frontend developer coming from the .Net world. I thought exactly the same but thought it might be due to lack of experience with JavaScript. Thanks for this comment, it confirms my suspicions!

 

Return function shortcut:

// Before
function foo() {
    bar();
    baz();
    return 1;
}

// After
function foo() {
    return bar(), baz(), 1;
}

Conditional shortcut variants:

// Before
return a ? a : b;

// After
return a || b;
// Before
return a ? b : c;

// After
return a && b || c;
// Before
return a && b ? c : d;

// After
return a && b && c || d;
// Before
if (a && b) {
    c = d;
}

// After
a && b && (c = d);
// Before
if (a) {
    b = c;
    d = e;
} else {
    b = e;
}
return f;

// After
return a && ((b = c), (d = e)) || (b = e), f;
 
 

Interesting.
Thank you for sharing that.

 

Useful examples 👍

The word hacks makes me feel you write about dirty shortcuts, but these are actually absolutely good solutions to every-day problems. I wouldn't call them hacks.

 

Eh.. I wouldn't use most of them in production code (like shortcutting over using an if statement).

 

Probably not in a class or function, but it's super useful in template code or jsx when you are in need of a terse expression, such as to say 'if object exists, render object.property'... user && user.name, etc

Leave terse to compilers unless it makes your expression more clear.

 
 

Thank you.
You do have a fair point.
But any word I thought of (tricks, shortcuts, etc) felt like a synonym for "cutting corners".

 

The replace all trick with regexp will work only if string to search doesn't contain regexp metacharacters like ., ^, etc. You'll have to escape them first. developer.mozilla.org/en-US/docs/W... provides an escape function.

function escapeRegExp(string) {
  return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}

'abc a;c a.c apc a.c'.replace(/a.c/g, 'X')
// gives "X X X X X"

'abc a;c a.c apc a.c'.replace(new RegExp(escapeRegExp('a.c'), 'g'), 'X')
// gives "abc a;c X apc X"

String.prototype.replaceAll is proposed to avoid such issues: github.com/tc39/proposal-string-re...

 

Interesting.
Thank you for sharing that with us.

 

That resize/empty an array is a kinda bad practice, imho, because you mutate the original array

 
 

You can chain it together many times AND you can do nicer looking deep undefined checks

‘niceobj && niceobj.maybeUndefined && niceObj.maybeUndefined.functionOrValue’

Way cleaner than if statements, but not as clean as typescripts “?.” operator

Sorry for the poor formatting. On mobile.

 

Oh I just found out the “?.” operator might be coming to JS too and it’s already in Babel.

I highly encourage you to take a look!

dev.to/akirautio/optional-chaining...

 

It's a good thing I read this article because if I had ever came across this I would have wondered what it was.

 

Felt the same way when I found out about it.

 

I also wanted to point out that #7 is especially useful when you are using ternary expressions, as you cannot chain an if statement within a big ternary, but you can using the && operator. A simple example would be using a ternary to write an if/else-if (rather than a basic if/else):

(condition
  ? truthyFunction()
  : condition2 && falsyFunction()
);

The corollary to this tip is using the || operator to basically say "If this is false, do the following":

condition || falsyFunction();
 

How exactly does this work?

var my_list = [1, 2, 3, 4, 5, 6, 7, 8, 9];

console.log( my_list.sort(function() {
return Math.random() - 0.5 //why 0.5?
}));

also, aren't arrays fixed size like in Java?

 

Math.random() returns a number between 0 and 1. -0.5 is so that the result is between -0.5 and 0.5. The end result is half the time the comparator will be negative and half the time it will be positive, basically a coin toss function. And no they're not, they're more like python lists.

 

Hi, Can you explain Why it is not like a coin toss function ? I thought it is...

 

The output of #5 (array shuffler) is not that random. I use my own implementation of Fisher-Yates:

const shuffle = arr => arr.reduceRight((r,_,__,s) => (r.push(s.splice(0|Math.random()*s.length,1)[0]), r),[])
 

Thak you man, you just saved me a lot of time.

 

I am new to programming so can someone tell me what ... Means? Its being used in number 2 and number 9. Everyone seems to know about as no one is talking about it.

And that set method could have come in handy a few days ago, gonna have to find the code and change my looping logic to get the unique data from array with set method

 

... meanse spread/rest operator. U would google it like "JS spread operator"

 

Thank you for replying, i kept searching for ... And nothing showed up. But the explanation was very clear and simple once i knew what to search.

 
y.length = x

This is really interesting. Good to know.

 

Flatten multidimensional array

Your example only works for 1 depth max, no?

 
 
 

Great post!

I noticed that you used a cover image I made for another DEV post.
dev.to/laurieontech/5-uses-for-the...

Would you mind crediting me? Or asking in the future.

 

Hi Laurie, my apologies for that.
I just googled images for JavaScript, didn't realise it was from another article.
I'll credit you in the article.

Later edit: Done

 

I understand. Google images are tough because they aren't great at noting what the rules are for image use. Admittedly I didn't enact a specific policy on mine either.

A couple good resources are unsplash.com/ for completely free images.

Or designer.io/en/ if you want to make your own. That's where I made this one :)

That's so awesome.
Thank you so much!

 

Will Endtest allow me to run a test on a webpage that is behind a company firewall? i.e. will the Extension let it run the script as if it's running from my laptop that is also behind the firewall?
It doesn't look like it works. The test script I set up can't access the internal webpage.

 
 

Hi, nice article!

Shuffling by -0.5 is not good in execution time.
It may be less harmful if the array is small.

 

Array shuffle trick is pretty neat, thanks for sharing!

 

First time seeing the length to shorten an array trick. Thanks for this 🙏

 

This was very informative, thanks for sharing.

 
 
 
 
 
 

Please don't use 7 if you work in a team.

 

How has no one mentioned the obvious advert for Endtest 😋

 
 

I don't get why you mention endtest in the article. And you do the same in all of your articles. Seems too shady and a marketing tactic

code of conduct - report abuse