Categories
JavaScript Best Practices

Adopting Better JavaScript Code Style — Error Handling and Comparisons

The way we write JavaScript can always be improved.

In this article, we’ll look at how to improve our code styles by improving the basic syntax we use in our code.

Error Handling

Error handling should be kept as simple as possible. If we encounter an error when running a function, we should throw an error.

For instance, we can throw an error if we encounter an invalid value as follows:

const greet = (name) => {
  if (typeof name !== 'string') {
    throw new Error('name not provided');
  }
  return `hi ${name}`;
}

In the code above, we check if name is a string. If it isn’t, then we throw an error.

Otherwise, we return the string with the greeting.

This is better than the alternative, which is returning error values:

const greet = (name) => {
  if (typeof name !== 'string') {
    return '';
  }
  return `hi ${name}`;
}

In the code above, we returned an empty string instead of throwing an error, so we hid the error from the developer using the function and the user.

It’s very easy to overlook error values since they aren’t immediately obvious. Unlike errors, which will show in the console immediately, we don’t see error values until we’re debugging.

This makes debugging harder since error values don’t show in the console.

Then if we need to handle errors, we can use the try...catch block as follows:

const greet = (name) => {
  if (typeof name !== 'string') {
    throw new Error('name not provided');
  }
  return `hi ${name}`;
}

try {
  greet();
} catch (ex) {
  console.log(ex);
}

In the code above, we have the following try...catch block:

try {
  greet();
} catch (ex) {
  console.log(ex);
}

Then since we didn’t pass in any argument into the greet function when we call it, we get an error in the console from the catch block.

To handle it better, we can choose to display an error message or something like that.

For async code, we should use promises as much as possible. Promises are rejected if errors are encountered, and like throwing errors in synchronous code, they also show up in the console.

For instance, if we have a promise that’s rejected as follows:

Promise.reject('error');

We can call catch on it to catch the error and handle it as follows:

Promise.reject('error')
  .catch(err => console.log(err));

In the code above, we called the catch method and in the catch method call, we passed in a callback to log the error.

Then we can get see errors and handle them in async code easily.

With the async and await syntax, we can catch errors from rejected promises as follows:

(async () => {
  try {
    await Promise.reject('error');
  } catch (err) {
    console.log(err);
  }
})();

As we can see, we just use try...catch like we did with synchronous code if we use the async and await syntax.

Comparison

=== and !== are always better than == and != .

This is because === and !== do not coerce the data types of their operands before doing the comparison.

On the other hand, == and != do data type coercion on their operands before doing any comparison.

By skipping typing one character, we introduced lots of headaches for ourselves because of the automatic type coercion.

Therefore, we should always just type the extra = sign and reduce the chances of bugs significantly.

To keep conditional expressions simple, we should use shortcuts as much as possible.

For instance, the following is bad:

if (condition === true) {
  // ...
}

This is bad because we don’t need to compare against true to check if something is true .

Instead, we should write:

if (condition) {
  // ...
}

Then we check if condition is truthy or not, which includes the value true .

If we use ternary expressions, we shouldn’t nest them. For instance, the following is good:

const foo = cond ? 'foo' : 'bar';

This is because we only have one condition cond and return 'foo' is cond is true and 'bar' otherwise.

However, we shouldn’t nest multiple ternary expressions together. So the following is bad:

const foo = cond1 ? cond2 ? 'foo' : 'bar' : 'baz';

Nesting makes the expression hard to understand. We’ve to put in the parentheses in our brains to compute the value in our heads so that we can understand what it’s doing.

Conclusion

Error handling is nest done by throwing errors and then handling them by catching them.

For async code, we can reject promises and then call catch or use the catch block to handle errors.

For conditionals, we should use the shortest way if we can. We also shouldn’t nest ternary expressions.

To do comparisons, we should use === and !== for comparisons so that we don’t have to worry about type coercions.

Categories
JavaScript Best Practices

Adopting Better JavaScript Code Style — Basic Syntax and Async

The way we write JavaScript can always be improved.

In this article, we’ll look at how to improve our code styles by improving the basic syntax we use in our code.

Naming Conventions

The names we use for identifiers like function names, class names, variable names, etc. should follow commonly accepted conventions.

They’re accepted because they make our code clear for most people.

To write good names, we should avoid single-letter names. We should be descriptive with our naming.

For instance, the following is bad:

let x;

because no one knows what x means.

However, the following is good:

let numFruits;

because we know from the variable name that it’ll store the number of fruits.

We also know that it’s a number, which is even better since JavaScript doesn’t have any data type annotations built-in to identify the type of a variable.

Likewise, the following is a bad way to name a function:

const q = () => {};

but the following is good:

const countFruits = () => {};

With the function name above, we actually know what the function actually does.

Notice that the good naming examples all use camelCase. This is the way to name most things, with the exception of class and constructor names.

For class and constructor function names, we should use PascalCase to name them.

For instance, the following is a good example of a class name:

class Fruit {}

for constructor functions, we should name it as follows:

function Fruit(){}

Semicolons

We should always add semicolons at the end of a new line. Because if we don’t the JavaScript interpreter will automatically add them to any place that it sees fit.

For instance, if we have something like:

const foo = ()=> {
  return
    'foo'
}

Then when we call foo , it’ll return undefined because the function ended after the return keyword. The 'foo' string isn’t considered to be part of the return statement.

Therefore, we should always add semicolons as follows:

const foo = () => {
  return 'foo';
}

Now the JavaScript Interpret knows that return 'foo'; is actually one line.

It also makes human reading it understand it better as well as it removed any ambiguity.

Comments

If we need comments, we need to standardize our comment schemes so that they’re consistent.

For a block comment, we write the following:

/* comment */

To make documentation easy, we should use JSDoc comments so that we can use them to create documentation for us automatically without doing extra manual work:

/**
 * Represents a fruit.
 * @constructor
 * @param {string} name - The name of a fruit.
 * @param {string} color - The color of a fruit.
 */
function Fruit(name, color) {
  this.name = name;
  this.color = color;
}

The code above has a big block comment with the parameters of the Fruit constructor function with the name and color parameters.

In the comment, we annotate the data type of the parameters so that it’s clear to everyone reading the code comment on what the function accepts.

Since JavaScript has no way to distinguish the data type of the parameters from within the code, the type annotation in the comments is useful.

The comment above is standard a JSDoc style comment.

Promises

If we deal with asynchronous code that deals with callbacks, then we should wrap them in a promise so that we can chain them easily.

For instance, if we need to run code with a delay, we should write a function that returns a promise to do that:

const delay = (ms) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log('delay');
      resolve();
    }, ms)
  })
}

In the code above, we have a delay function that returns a promise that runs the serTimeout function inside it to run some code.

Then within the setTimeout callback, we call resolve to fulfill the promise.

This way, we won’t get callback hell by nesting async callbacks many levels deep.

To handle errors, we can write the following code:

const fs = require('fs');

const readFile = (filename) => {
  return new Promise((resolve, reject) => {
    fs.readFile(filename,(err, data) => {
      if (err) {
        reject(err);
      }
      resolve(data);
    });
  })
}

(async () => {
  const data = await readFile('foo.txt');
  console.log(data.toString())
})();

In the code above, we have the readFile function, which returns a promise that runs the fs.readFile function. Inside the readFile ‘s callback, if err is defined, then we call reject to reject the promise. We can resolve the promise if data is provided.

Then we can use async and await to use the promise as we did in the last few lines of code.

Conclusion

Names and comments should be consistent. Names should be self-documenting with descriptive names and in the case that is commonly accepted.

Also, we should wrap async code that aren’t promises with promises so that we can chain them.

Categories
JavaScript Best Practices

Ways to Write Better JavaScript — Use Modern JavaScript Features

The way we write JavaScript can always be improved. As the language evolves and more convenient features are added, we can also improve by using new features that are useful.

In this article, we’ll look at some modern JavaScript features that we should use to make our lives easier.

**async** and**await**

async and await lets us chain promises in a shorter way. For instance, we can write:

(async () => {
  const res = await fetch('https://api.agify.io/?name=michael');
  const data = await res.json();
  console.log(data);
})();

instead of:

fetch('https://api.agify.io/?name=michael')
  .then(res => res.json())
  .then(data => console.log(data))

With async and await , we eliminated the need to call then and return promises in callbacks.

This is much better than nesting anything. This makes our code easier to read and write.

To catch errors with async and await , we can use try...catch with async function as follows:

(async () => {
  try {
    const res = await fetch('https://api.agify.io/?name=michael');
    const data = await res.json();
    console.log(data);
  } catch (err) {
    console.log(err);
  }
})();

We just use the existing try...catch syntax to catch errors.

With the old catch method, it’s a bit longer:

fetch('https://api.agify.io/?name=michael')
  .then(res => res.json())
  .then(data => console.log(data))
  .catch(err => console.log(err))

Then catch will catch the error and display the content.

The 2 are equivalent. It’s just that async and await are shorter than the old then and catch methods.

**let** and**const**

let and const are must-use when we need to declare variables or constants respectively.

They completely replace var and does a much better job than var for declaring variables.

let and const are both block-scoped, and the variables and constants declared with them can only be used after they’re declared.

On the other hand, var is function scoped and the variable declaration itself is hoisted to the top of the code without the value.

var causes so much confusion that they all should be replaced with let and const .

const should also be used so that values declared with them can’t be reassigned. They also must have an initial value assigned to them immediately when it’s declared.

Probably most entities should be declared with const since most of them shouldn’t be reassigned to a different value.

Note that values declared with const are still mutable, they just can’t be reassigned.

For instance, if const is used to declare an array, we can call push to add more items to the array.

Object properties can also be assigned to different values.

Arrow Functions

Arrow functions are another must-use modern JavaScript feature. It’s shorter and also we don’t have to worry about the value of this inside an arrow function.

Legacy constructs like the arguments object also can’t be used within an arrow function, which is good.

We can use it to declare anonymous functions for callback or we can assign them to a variable or constant.

For instance, we can write:

fetch('https://api.agify.io/?name=michael')
  .then(res => res.json())
  .then(data => console.log(data))

Then we have arrow functions in the then callback which returns promises in the first then callback and calls console.log in the 2nd then callback.

As we can see, we returned something without using the return keyword in single-line arrow functions.

This is also much shorter than using the traditional functions since we don’t have to type out the function keyword.

However, if we have a multiline arrow function, then we have to use the return keyword and parentheses to return a value.

For instance, if we have a long function, we write something like:

const sum = (...nums) => {
  return nums.reduce((a, b) => a + b, 0)
}

Spread Operator

The spread operator lets us copy and combine objects in ways that are hard to do without it.

For instance, with objects, we can write:

const obj1 = {
  a: 1
};
const obj2 = {
  b: 2
};
const merged = {
  ...obj1,
  ...obj2
}

The merged is {a: 1, b: 2} since we spread the entries from obj1 and obj2 into a new object.

The only other way is to use the Object.assign method, which we use as follows:

const obj1 = {
  a: 1
};
const obj2 = {
  b: 2
};
const merged = Object.assign({}, obj1, obj2);

We can also use it to merge arrays into one. We can use it as follows:

const arr1 = [1, 2];
const arr2 = [3, 4];
const merged = [...arr1, ...arr2];

The code above will spread arr1 and arr2 ‘s entries into the merged array.

And so merged is [1, 2, 3, 4] .

Conclusion

Using modern JavaScript features is a must for any JavaScript app to keep the code clean and short.

Some useful features include the spread operator, arrow functions, let and const , and async and await .

Categories
JavaScript Best Practices

Ways to Write Better JavaScript — Use TypeScript

The way we write JavaScript can always be improved. As the language evolves and more convenient features are added, we can also improve by using new features that are useful.

In this article, we’ll look at some ways to write better JavaScript by using TypeScript.

Use TypeScript

TypeScript is a natural extension to JavaScript. It lets us write JavaScript code that’s type-safe. Therefore, we can use it to prevent lots of data type errors that would otherwise occur if we didn’t use TypeScript.

Also, it provides autocomplete for things that otherwise wouldn’t have the autocomplete feature like many libraries. They use TypeScript type definitions to provide autocomplete for text editors and IDEs to make our lives easier.

TypeScript doesn’t turn JavaScript into a different language. All it does is add type checking to JavaScript by various type-checking features.

Therefore, all the knowledge that is used for JavaScript all apply to TypeScript.

For instance, we can create a function with TypeScript type annotations as follows:

const foo = (num: number): number => {
  return num + 1;
}

In the code above, we have the foo function with a num parameter that’s set to the type number . We also set the return type to number by specifying the type after the : .

Then if we call the function with a number, the TypeScript compiler will accept the code.

Otherwise, it’ll reject the code and won’t build the code. This is good because JavaScript doesn’t stop this from happening.

Interfaces

TypeScript provides us interfaces so that we know the structure of an object without logging the object or checking the value otherwise.

For instance, we can create one as follows:

interface Person {
    name: string;
    age: number;
}

Then we can use it as follows:

const person: Person = { name: 'jane', age: 10 }

If we miss any of these properties, then we’ll get an error as the TypeScript compiler is looking for them.

We can also use it to enforce a class implementation as follows:

interface PersonInterface {
    name: string;
    age: number;
}

class Person implements PersonInterface {
    name: string;
    age: number;
    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }
}

In the code above, we have both the name and age fields. If we skip any of them, then we’ll get an error from the TypeScript compiler.

If we want to embrace the dynamic typing nature of JavaScript, we can add dynamic index signatures to JavaScript. Also, there’re union and intersection types to combine different types into one.

For instance, we can use it as follows:

interface PersonInterface {
    name: string;
    age: number;
    [key: string]: any;
}

In the code above, we have:

[key: string]: any;

to allow dynamic keys in anything that implements PersonInterface that has anything as a value.

Then we can have any property in addition to name and age in any class that implements PersonInterface or an object that’s cast to the PersonInterface type.

Union types let us join different types together. For instance, we can use it as follows:

interface Person {
    name: string;
    age: number;
}

interface Employee {
    employeeId: string;
}

const staff: Person | Employee = {
    name: 'jane',
    age: 10,
    employeeId: 'abc'
}

In the code above, the | is the union type operator. It lets us combine both the keys from both interfaces into one without creating a new type.

Another good thing about TypeScript is nullable properties. We can make properties optional with the ? operator.

For instance, we can use the following code:

interface Person {
    name: string;
    age?: number;
}

With the ? operator, we made age an optional property.

typeof Operator

Another great feature of TypeScript is the typeof operator, which lets us specify that something has the same type as something else.

For instance, we can use it as follows:

const person = {
    name: 'jane',
    age: 10,
}

const person2: typeof person = {
    name: 'john',
    age: 11,
}

In the code above, we have the person2 object, which has the same type as person since we specified that with typeof person . Then person2 must have the name and age properties or we’ll get an error.

As we can see, we don’t need to specify any interfaces or classes explicitly to specify types. This is handy for getting the types of imported libraries that don’t come with type definitions.

Conclusion

With TypeScript, we made refactoring easy since it’s harder to break the existing code with the type and structure checks that it provides.

It also makes communication easier because we know the type and structure of our objects, classes, and return value of functions.

Categories
JavaScript Basics

The Destructuring Assignment in JavaScript

JavaScript is the main language for front-end development. It’s also used a lot for back-end development.

The language has gotten much better in the last few years.

In this article, we’ll look at one of the better features of JavaScript, which is the destructuring assignment syntax.


Destructuring Syntax on Arrays

The destructuring syntax is used for assigning object and array entries to their own variables.

For instance, we can write the following code to assign array entries to individual variables:

const [a, b] = [1, 2];

Then, the destructuring assignment syntax assigns the entries to the variables located in the same position.

Therefore, a is 1 and b is 2.

We don’t have to assign all of them to variables, so we can write something like:

const [a] = [1, 2];

Then a is 1.

Also, we can assign variables that haven’t been assigned a variable to an array.

For instance, we can write:

const [a, ...b] = [1, 2, 3];

The three dots specify that we are assigning the array entries that haven’t been assigned to a variable to an array.

Therefore, a is 1 and b is [2, 3].

We can also set a default value for variables of the destructuring assignment. For instance, we can write:

const [a, b, c = 3] = [1, 2];

Then c is 3 because we didn’t assign anything to it, so the default value of 3 is assigned to it.

Nested values also work. For instance, we can write:

const [{
  foo
}, b] = [{
  foo: 1
}, 2];

Then the JavaScript interpreter will match the shape of the object and the position in the array and do the destructuring assignment accordingly.

Therefore, the value of foo on the right is assigned to foo on the left and we get that foo is 1.


Destructuring Syntax on Objects

We can use the destructuring syntax on objects to assign property values to a variable with the same name as the corresponding property name.

For instance, we can write:

Then a is 1 and b is 2 since a is on the left side and a is 1, so the JavaScript interpreter matches the property name and variable name and makes the assignment by that name.

The same is done for property b .

We can set it to a different variable name also. To do this, we write:

Then we assign the 2 to c by matching the property b on the right side to b on the left side.

Like the array destructuring syntax, we can assign a default value to the variable on the left side.

For instance, we can write:

Then c is set to 3. when there’s no c property in the object. Therefore, c would be 3 in the code above.

The destructuring assignment also works with nested values. For example, we can write:

The example will set b to 3 since the JavaScript interpreter matched the structure of the objects on the left and right and then set b on the left to 3.

Values that aren’t assigned to a variable can be assigned to another object as follows:

The rest will have:

{b: 2, c: 3}

As the value since we used the ... operator.


Swapping Variables

A great application of the destructuring syntax is swapping variable values.

For instance, if we have:

let a = 1,
  b = 2;
[a, b] = [b, a];

Then a is 2 and b is 1 after the application of the destructuring syntax.

It’s much less taxing on our brains since we don’t have to have temporary placeholder variables or add and subtract values to swap values.


For…of Loop

The for...of loop works with the destructuring syntax.

For instance, we can write:

Then we get:

Jane Smith
Don Smith

From the console.log output. It’s very convenient for extracting content out of the object that’s being iterated on.


Conclusion

We can use the JavaScript destructuring syntax to assign property values and object entries to variables.

It works with nested objects. We can assign extra entries to arrays with the ... operator.

The for...of loop also works with the destructuring syntax.

To write clean code, we should use this now.