JavaScript Wizard: Tips and Tricks

JavaScript Wizard: Tips and Tricks

JavaScript Wizard: Tips & Tricks

In 2017, the second most in-demand language in job openings was JavaScript, only beaten by Java.

Indeed, if you want to secure a safe position as a desirable software engineer, knowing how to handle this popular language can be very beneficial. If you’re already there, learning about some of the hidden corners of JavaScript can help you prevent a bit of headache every now and then 😉

List of most in-demand languages in job openings made by [Indeed.com](https://cdn.hashnode.com/res/hashnode/image/upload/v1600277724940/F7GrvZpOG.html) in late 2017. [[source](https://stackify.com/popular-programming-languages-2018/)]List of most in-demand languages in job openings made by Indeed.com in late 2017. [source]

In this article, I’m going to be covering 8 neat JavaScript tips & tricks that you may not have heard of. This article is both for newcomers at JavaScript, and the one with more intermediate experience.

1. Number

When parsing numbers in JavaScript, you’ve probably both seen and used the global functions parseInt() and parseFloat().

JavaScript is slowly moving away from global functions like the above, in favor of using modules. Both parseInt() and parseFloat() belong to the Number object, and can be called like Number.parseInt()

In JavaScript, all numbers are of the same datatype ‘number’ which are all floating points. More specifically, JavaScript uses the double-precision floating-point format. The Number object is created with a Number() constructor and the easiest way to parse a number from a string (if you don’t need to use a radix), is to pass the string to the constructor as an argument.

const num = Number('42.5')

Additionally, the Number object has a collection of handy functions for working with numbers and mathematical operations.

Here’s an example of some of these functions in use

// The Number.isFinite() method determines whether the passed value is a finite number.
Number.isFinite(42 / 0); // false
Number.isFinite(42 / 2); // true

// The Number.isInteger() method determines whether the passed value is an integer.
Number.isInteger(13 / 11); // false
Number.isInteger(5 + 7); // true

// The toPrecision() method returns a string representing the Number object to the specified precision.
Number(42.0324).toPrecision(4); // 42.03
Number(0.00031).toPrecision(3); // 0.000310

// The toExponential() method returns a string representing the Number object in exponential notation.
Number(3240213).toExponential(3); // 3.240e+6
Number(0.000001543).toExponential(5); // 1.54300e-6

2. Exponentiationinfix operator

When you need to raise some number to the power of some other number, you’ve probably been used to using Math.pow(a, b) As of ECMAScript 2016 (ES7), you can now use the exponentiation infix operator ** instead.

// Before ES7
Math.pow(9, 4); // 6561

// Now
9 ** 4 // 6561

3. Truthy/falsy boolean conversion

In JavaScript, any value can be evaluated in a boolean context. If a value is evaluated to true it is said to be truthy and falsy otherwise.

The following values will always be evaluated to false in a boolean context.

  • false

  • null

  • undefined

  • 0

  • '' or "" (empty string)

  • NaN

Anything else will be evaluated to true in a boolean context.

Sometimes we want to convert a value that is not a boolean, into a boolean. We can accomplish that using the !! operator, also called the not-not operator.

!!null // false
!!undefined // false
!!NaN // false
!!"" // false
!!0 // false

!!1 // true
!!{} // true
!![] // true
!!"hi, mom" // true

Note that !! in itself is not a logical operator, but a combination of two ! operators used sequentially. The first ! will evaluate the value of whatever comes behind it in a boolean context, coercing it into a boolean and negate it. The second ! will negate this boolean, causing the desired effect of converting a truthy/falsy value into its boolean representation.

Another way this can be accomplished is by using the Boolean object.

NB: For values that are not booleans, use `Boolean* as a function rather than creating a new instance of theBoolean` object.*

// Use it like this
const x = Boolean("Hi, mom");

// Not like this
const x = new Boolean("Hi, mom");

4. Object.entries

Maybe you were already aware that you can use Object.keys() to return a list containing the key-names of an object. This is handy when you want to iterate through an object like so

const obj = {
  msg: "hi",
  to: "mom",
  year: 2019
}

Object.keys(obj).forEach(k => {
  console.log(k);
});

// 'msg'
// 'to'
// 'year'

But you might not be aware that you can use Object.entries() to return a list of entries containing both the key-name and the value of an object.

const obj = {
  msg: "hi",
  to: "mom",
  year: 2019
}

Object.entries(obj).forEach(([k, v]) => {
  console.log(k + " : " + v);
});

// 'msg : hi'
// 'to : mom'
// 'year : 2019'

If you didn’t figure it out yourself already, you can of course also return a list containing only the values, by using Object.values() like so

const obj = {
  msg: "hi",
  to: "mom",
  year: 2019
}

Object.values(obj).forEach(v => {
  console.log(v);
});

// 'hi'
// 'mom'
// '2019'

5. Rest operator on objects

In ES6, the rest and spread operator was introduced. They have very different effects, but are both used by setting three dots ...

  • Spread operator allow iterables to be expanded into single arguments/element.

  • Rest operator collects all remaining elements into an iterable.

The rest operator can be applied to arrays as well as objects, and this can be a strong tool when used correctly.

By combining destructuring and the rest operator on objects, we can easily extract wanted properties from an object, leaving the remaining properties in an object for itself.

const obj = {
  msg: "hi",
  to: "mom",
  year: 2019,
  seen: false,
}

const { year, ...remainingObj } = obj;

console.log(year);
// 2019

console.log(remainingObj); 
// {
//  msg: 'hi',
//  seen: false,
//  to: 'mom'
// }

This is also really handy when we want to clean certain properties from an object. No need for iterating through the whole object and creating a new clean object.

If you want to read more about the spread and rest operator, I suggest you read the article: Recursion in JavaScript with ES6, destructuring and rest/spread by Hugo Di Francesco.

6. Finally

Promises have become a huge thing in JavaScript. As the entirety of this topic is beyond the scope of this article, I want to focus on a new function; finally() that has been added to JavaScript Promises as an instance method and can be used in extension with then().catch()

finally() is called without any value and is called regardless of a promise being resolved or rejected. That is, it is executed no matter what.

const aPromise = new Promise((resolve, reject) => resolve("alles gut"));

aPromise
  .then(res => console.log(res)) // alles gut
  .catch(err => console.log(err))
  .finally(() => {
    // This is always executed!
  });

It can also be used with the ES7 async/await.

const aPromise = new Promise((resolve, reject) => reject("uhff"));

const resolveThePromise = async () => {
  try {
    const msg = await aPromise;
    console.log(msg); 
  } 
  catch(err) {
    console.log(err); // uhff
  }
  finally {
    // this is still always executed!
  }
}

resolveThePromise();

If you want a more thorough walkthrough of JavaScript’s promises, I suggest you read the article: Understanding promises in JavaScript by Gokul N K.

7. for await…of

While we’re at the topic of promises, I want to mention another incredibly useful feature. The brand new for await...of feature from ES8 lets us iterate asynchronously through a list of promises. The for await…of loop will effectively wait for the promise to resolve before continuing to the next iteration.

const promises = [
  new Promise(resolve => resolve(console.log("Hi"))),
  new Promise(resolve => resolve(console.log("mom"))),
  new Promise(resolve => resolve(console.log("whatsup!")))
];


for await (const msg of promises) {
  console.log(msg);
}

// 'Hi'
// 'mom'
// 'whatsup!'

Note how every msg at iteration is the resolved value of the promises, rather than a promise itself. In this case, we can also be sure that we will have the promises logged out in the correct order.

NB. This is feature is experimental and behavior is expected to change in the future. Moreover, this is not yet supported in IE and Edge, and the support in Node.js is unknown.

8. FlatMap

flatMap() is another ES8 proposal used to perform one-level flattening of arrays. The same behavior can be achieved by using map() and reduce() but applying flatMap() is more simple and readable.

// an array of arrays
const numberArrays = [[9], [3], [8], [13], [16]];

// Perform operation, and flatten array
numberArrays.flatMap(x => x * 2);

// [18, 6, 16, 26, 32]

In this other example, it might get more clear where the use of flatMap() can be really convenient. Here, we’re generating a list of words from a list of sentences.

const sentences = ["Hi mom", "what time are we", "having dinner"];

sentences.flatMap(x => x.split(" "));

// ["Hi", "mom", "what", "time", "are", "we", "having", "dinner"];

That’s it! I hope you enjoyed reading, and if you have any questions or feedback, please feel free to comment below. If you liked this article, give the clap 👏 button a couple of hits!