Tips for JavaScript Developers

by Janeth Kent Date: 08-06-2020 javascript tips tutorial


Another year is over and JavaScript is constantly changing. However, there are some tips that can help you write in 2019 clean and efficient code that scales. Below is a list of 9 pragmatic suggestions.

 

async / await

 

Are you still trapped in callback hell?

Don't use callbacks unless it's completely necessary, such as a library or for performance reasons. Promises are totally fine, but if your codebase gets bigger, they're a little awkward to use.

Today, the solution is to implement async / wait, which makes my code much cleaner to read and improve. In fact, you can wait for every JavaScript Promise if a a library you use returns a promise, just wait for it. Async / await is actually only syntactic sugar around promises. You just need to add the async keyword in front of a function to make your code work.

Here's a fast example:

 
async function getData() {
const result = await axios.get('https://dube.io/service/ping')
const data = result.data
console.log('data', data)
return data
}
getData()
 

Note that await on the top level is not possible, you can only call an asyncfunction.

async / await was introduced with ES2017, so make sure to transpile your code.

 

async control flow

 

It is often necessary to collect several datasets and do something for each one or complete a task after all async calls have returned a value.

for…of

Let's say we've got a couple of Pokemon on our page, and we need to get detailed information. We don't want to wait until all calls are finished, especially if we don't know how many, but we want to update our data sets as soon as we get something back.

To loop through an array and execute async code within the block, we can use a for...of ; the execution is stopped until each call is successful.

It is important to keep in mind that if you do something like this in your code, there may be performance bottlenecks, but keeping in your tool set is very useful. The following is an example:

 
import axios from 'axios'
let myData = [{id: 0}, {id: 1}, {id: 2}, {id: 3}]
async function fetchData(dataSet) {
for(entry of dataSet) {
const result = await axios.get(`https://ma-no.org/gamers/${entry.id}`)
const newData = result.data
updateData(newData)
console.log(myData)
}
}
function updateData(newData) {
myData = myData.map(el => {
if(el.id === newData.id) return newData
return el
})
}
fetchData(myData)
 

Promise.all

What if you want to pick up all gamers at the same time? Since all promises can be awaited, just use Promise.all:

 
import axios from 'axios' 
let myData = [{id: 0}, {id: 1}, {id: 2}, {id: 3}]
async function fetchData(dataSet) {
const gamersPromises = dataSet.map(entry => {
return axios.get(`https://ma-no.org/gamers/${entry.id}`)
})
const results = await Promise.all(gamersPromises)
results.forEach(result => {
updateData(result.data)
})
console.log(myData) 
}
function updateData(newData) {
myData = myData.map(el => {
if(el.id === newData.id) return newData
return el
})
}
fetchData(myData)
 

Destructuring & default values

 

Let's go back to our previous example where we do this:

 
const result = axios.get(`https://ma-no.org/gamers/${entry.id}`)
const data = result.data
 

We can use destructuring to only take one or some of the values from an object or array. We would like to do it:

 
const data = result.data
 

We saved one line of code! Yay! You can also rename your variable:

 
const { data: newData } = await axios.get(...)
 

Giving default values when destructing is another nice trick. This guarantees that you never end up undefined and that you don't have to manually check the variables.

 
const { id = 5 } = {}
console.log(id) // 5
 

These tricks can also be used with function parameters, for example:

 
function calculate({operands = [1, 2], type = 'addition'} = {}) {
return operands.reduce((acc, val) => {
switch(type) {
case 'addition':
return acc + val
case 'subtraction':
return acc - val
case 'multiplication':
return acc * val
case 'division':
return acc / val
}
}, ['addition', 'subtraction'].includes(type) ? 0 : 1)
}
console.log(calculate()) // 3
console.log(calculate({type: 'division'})) // 0.5
console.log(calculate({operands: [2, 3, 4], type: 'multiplication'})) // 24
 

The example may seem somewhat confusing at first, but take your time and play with it. The default values are used if we do not pass any values to our function as arguments. Once we start passing values, for non - existent arguments only default values are used.

 

Truthy & falsy values

 

Some checks for existing values are a thing of the past when default values are used. However, it is very nice to know that you can work with true and false values. This improves your code and saves a few instructions to make it more eloquent. I often see people doing something like this:

 
if(myBool === true) {
console.log(...)
}
// OR
if(myString.length > 0) {
console.log(...)
}
// OR
if(isNaN(myNumber)) {
console.log(...)
}
 

To really take full advantage of these statements, you have to understand what truthy and false values are. Here's a small overview:

Falsy

  • strings with the length of 0
  • the number 0
  • false
  • undefined
  • null
  • NaN

Truthy

  • empty arrays
  • empty objects
  • Everything else

Note that when checking for truthy / falsy values, there is no explicit comparison, which equates to checking with double equal signs == and not three ===. In general, it behaves the same way but there are certain situations where you will end up with a bug. For me, it happened mostly with the number 0.

 

Logical and ternary operators

 

Again, they are used to shorten your code, saving you precious lines of code. Often they are nice tools and help keep your code clean, but they can also create some confusion, especially when chaining them.

Logical operators

The logical operators basically combine two expressions and will return either true, false or the matching value and are represented by && , meaning “and” — as well as ||, meaning “or”. Let’s have a look:

 
console.log(true && true) // true
console.log(false && true) // false
console.log(true && false) // false
console.log(false && false) // false
console.log(true || true) // true
console.log(true || false) // true
console.log(false || true) // true
console.log(false || false) // false
 

We can combine logical operators with our knowledge from the last point, truthful and false values. The following rules apply when using logical operators:

  • && : The first falsy value gets returned, if there is none, the last truthy value is being returned.
  • ||: The first truthy value gets returned, if there is none, the operation will equal to the last falsy value.

 
console.log(0 && {a: 1}) // 0
console.log(false && 'a') // false
console.log('2' && 5) // 5
console.log([] || false) // []
console.log(NaN || null) // null
console.log(true || 'a') // true
 

Ternary operator

The ternary operator is much like the logical operator, but it has three parts:

  • The comparison, which will either be falsy or truthy
  • The first return value, in case the comparison is truthy
  • The second return value, in case the comparison is falsy

Example:

 
const lang = 'German'
console.log(lang === 'German' ? 'Hallo' : 'Hello') // Hallo
console.log(lang ? 'Ja' : 'Yes') // Ja
console.log(lang === 'French' ? 'Bon soir' : 'Good evening') // Good evening
 

Optional chaining

 

Did you ever have the problem of accessing a property of a nested object without knowing whether the object or one of the sub - properties exists? You'll likely end up with something like this:

 
let data
if(myObj && myObj.firstProp && myObj.firstProp.secondProp && 
myObj.firstProp.secondProp.actualData) data = 
myObj.firstProp.secondProp.actualData
 

This is boring and tedious and there is a better way, at least a proposed way (continue to read how to make it possible). Optional chaining is called and works as follows:

 
const data = myObj?.firstProp?.secondProp?.actualData
 

Class properties & binding

 

Binding functions in JavaScript is a common task. With the introduction of arrow functions in the ES6 spec, we now have a way to automatically link functions to to the declaration context - very useful and commonly used by developers of JavaScript.

When classes were first adopted, arrow functions could no longer be used because class methods had to be declared in a specific way.

We had to bind functions elsewhere, like in the constructor (best practice with React.js)

We can use arrow functions again with the class property syntax and obtain the advantages of auto - binding.

Arrow function can now be used inside the class. Here is an example with _increaseCount being bound:

 
class Counter extends React.Component {
constructor(props) {
super(props)
this.state = { count: 0 }
}
render() {
return(
<div>
<h1>{this.state.count}</h1> 
<button onClick={this._increaseCount}>Increase Count</button>
</div>
)
}
_increaseCount = () => {
this.setState({ count: this.state.count + 1 })
}
}
 

Use parcel

 

As a frontend developer, you have almost certainly encountered bundling and transpiling code. The de-facto standard was a webpack for a long time. We used version 1 webpack first. Fiddling with all the different configuration options, we spent countless hours trying to get the bundling up and running.

Parcel does pretty much everything for you out of the box, while still giving you the possibility to change it, if necessary. It also supports a plugin system, similar to webpack or babel and is incredibly fast. If you don’t know parcel, I definitely suggest you check it out!

 

Write more code on your own

 

This is a nice subject of discussion. We've had many different conversations about it. Many people even use a component library such as bootstrap for CSS. We still see people for JavaScript using jQuery and small libraries for validation, sliders, etc.

While using libraries may make sense, we strongly recommend that you write more code instead of blindly installing npm packages. When there are large libraries (or even frameworks) where a whole team builds it, such as moment.js or react-datepicker, trying to code it yourself doesn't make sense.

You can write most of the code you use yourself, though. This gives you three main benefits:

1. You know exactly what's going on in your code

2. Sometime you'll begin to really understand programming and how things work under the hood.

3. You prevent the bloating of your codebase

It's easier to use a npm package at first. To implement some functionality on your own, it will take more time. But what if the package doesn't really work as expected and you need to switch to another, spending even more time reading how your API is set up.

You can customize it 100% to your use when you implement it on your own :-).

 
by Janeth Kent Date: 08-06-2020 javascript tips tutorial hits : 7612  
 
Janeth Kent

Janeth Kent

Licenciada en Bellas Artes y programadora por pasión. Cuando tengo un rato retoco fotos, edito vídeos y diseño cosas. El resto del tiempo escribo en MA-NO WEB DESIGN AND DEVELOPMENT.

 
 
 

Related Posts

How to use the endsWith method in JavaScript

In this short tutorial, we are going to see what the endsWith method, introduced in JavaScript ES6, is and how it is used with strings in JavaScript. The endsWith method is…

What are javascript symbols and how can they help you?

Symbols are a new primitive value introduced by ES6. Their purpose is to provide us unique identifiers. In this article, we tell you how they work, in which way they…

Callbacks in JavaScript

Callback functions are the same old JavaScript functions. They have no special syntax, as they are simply functions that are passed as an argument to another function. The function that receives…

How to create PDF with JavaScript and jsPDF

Creating dynamic PDF files directly in the browser is possible thanks to the jsPDF JavaScript library. In the last part of this article we have prepared a practical tutorial where I…

How to make your own custom cursor for your website

When I started browsing different and original websites to learn from them, one of the first things that caught my attention was that some of them had their own cursors,…

Node.js and npm: introductory tutorial

In this tutorial we will see how to install and use both Node.js and the npm package manager. In addition, we will also create a small sample application. If you…

How to connect to MySQL with Node.js

Let's see how you can connect to a MySQL database using Node.js, the popular JavaScript runtime environment. Before we start, it is important to note that you must have Node.js installed…

JavaScript Programming Styles: Best Practices

When programming with JavaScript there are certain conventions that you should apply, especially when working in a team environment. In fact, it is common to have meetings to discuss standards…

Difference between arrow and normal functions in JavaScript

In this tutorial we are going to see how arrow functions differ from normal JavaScript functions. We will also see when you should use one and when you should use…

JavaScript Arrow functions: What they are and how to use them

In this article we are going to see what they are and how to use JavaScript Arrow Functions, a new feature introduced with the ES6 standard (ECMAScript 6). What are Arrow…

How to insert an element into an array with JavaScript

In this brief tutorial you will learn how to insert one or more elements into an array with JavaScript. For this we will use the splice function. The splice function will not…

What is the difference between primitives types and objects in JavaScript?

In this short tutorial we are going to look at the differences between primitive types and objects in JavaScript. To start with, we're going to look at what primitive types…