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.

Categories
JavaScript Basics

Using the Destructuring Assignment Syntax in JavaScript

The destructuring assignment syntax is a JavaScript syntax feature that was introduced in the 2015 version of JavaScript and lets us unpack a list of values of an array or key-value pairs of an object into individual variables.

It’s very handy for retrieving entries from arrays or objects and setting them as values of individual variables. This is very handy because the alternative was to get an entry from an array from an index and then setting them as values of variables for arrays.

For objects, we have the value from the key and set them as values of variables.


Array Destructuring

We can use the destructuring assignment syntax easily in our code. For arrays, we can write:

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

Then, we get 1 as the value of a and 2 as the value of b because the destructing syntax unpacked the entries of an array into individual variables.

Note that the number of items in the array does not have to equal the number of variables. For example, we can write:

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

Then a is still 1 and b is still 2 because the syntax only sets the variables that are listed in the same order as the numbers appeared in the array. So, 1 is set to a, 2 is set to b, and 3 is ignored.

We can also use the rest operator to get the remaining variables that weren’t set to variables. For example, we can have:

const [a,b,...rest] = [1,2,3,4,5,6]

Then, rest would be [3,4,5,6] while we have a set to 1 and b set to 2. This lets us get the remaining array entries into a variable without setting them all to their own variables.

We can use the destructuring assignment syntax for objects as well. For example, we can write:

const {a,b} = {a:1, b:2};

In the code above, a is set to 1 and b is set to 2 as the key is matched to the name of the variable when assigning the values to variables.

Because we have a as the key and 1 as the corresponding value, the variable a is set to 1 as the key name matches the variable name. It is the same with b. We have a key named b with a value of 2, because we have the variable named b, we can set b to 2.

We can declare variables before assigning them with values with the destructuring assignment syntax. For example, we can write:

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

Then, we have a set to 1 and b set to 2 because a and b that were declared are the same ones that are assigned.

As long as the variable names are the same, the JavaScript interpreter is smart enough to do the assignment regardless of whether they’re declared beforehand or not.

We need the parentheses on the line so that the assignment will be interpreted as one line and not individual blocks with an equal sign in between, because two blocks on the same line aren’t valid syntax.

This is only required when the variable declarations happen before the destructuring assignment is made.

We can also set default values for destructuring assignments. For instance:

let a,b;
([a=1,b=2] = [0])

This is valid syntax. In the code above, we get that a is 0 because we assigned 0 to it. b is 2 because we didn’t assign anything to it.

The destructuring assignment syntax can also be used for swapping variables, so we can write:

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

b would become 1 and a would become 2 after the last line of the code above. We no longer have to assign things to temporary variables to swap them, and we also don’t have to add or subtract things to assign variables.

The destructuring assignment syntax also works for assigning returned values of a function to variables.

So, if a function returns an array or object, we can assign them to variables with the destructuring assignment syntax. For example, if we have:

const fn = () =>[1,2]

We can write:

const [a,b] = fn();

To get 1 as a and 2 as b with the destructuring syntax because the returned array is assigned to variables with the syntax.

Similarly, for objects, we can write:

const fn = () => {a:1, b:2}
const {a,b} = fn();

We can ignore variables in the middle by skipping the variable name in the middle of the destructuring assignment. For example, we can write:

const fn = () => [1,2,3];
let [a,,b] = fn();

We get a with the value of 1 and b with the value of 3, skipping the middle value.

It’s important to know that if we use the rest operator with a destructuring assignment syntax, we cannot have a trailing comma on the left side, so this:

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

Will result in a SyntaxError.


Object Destructuring

We can use the destructuring assignment syntax for objects as well. For example, we can write:

const {a,b} = {a:1, b:2};

In the code above, a is set to 1 and b is set to 2 because the key is matched to the name of the variable when assigning the values to variables.

As we have a as the key and 1 as the corresponding value, the variable a is set to 1 because the key name matches the variable name. It is the same with b. We have a key named b with a value of 2, because we have the variable named b, we can set b to 2.

We can also assign it to different variable names, so we don’t have to set the key-value entries to different variable names. We just have to add the name of the variable we want on the value part of the object on the left side, which is the one we want to assign it to, like the following:

const {a: foo, b: bar} = {a:1, b:2};

In the code above, we assigned the value of the key a to foo and the value of the key b to the variable bar. We still need a and b as the keys on the left side so they can be matched to the same key names on the right side for the destructuring assignment.

However, a and b aren’t actually defined as variables. It’s just used to match the key-value pairs on the right side so that they can be set to variables foo and bar.

Destructuring assignments with objects can also have default values. For example, we can write:

let {a = 1, b = 2} = {a: 3};

Then, we have a set to 3 and b set to 2 which is the default value as we didn’t have a key-value pair with a key named b on the right side.

Default values can also be provided if we use the destructuring syntax to assign values to variables that are named differently from the keys of the originating object. So, we can write:

const {a: foo=3, b: bar=4} = {a:1};

In this case, foo would be 1 and bar would be 4 because we assigned the left bar with the default value, but assigned foo to 1 with the destructuring assignment.

The destructuring assignment also works with nested objects. For example, if we have the following object:

let user = {
  id: 42,
  userName: 'dsmith',
  name: {
    firstName: 'Dave',
    lastName: 'Smith'
  }
};

We can write:

let `{`userName`,` name`: { firstName }} =` user;

To set displayName to 'dsmith' , and firstName to 'Dave'. The lookup is done for the whole object and, so, if the structure of the left object is the same as the right object and the keys exist, the destructuring assignment syntax will work.

We can also use the syntax for unpacking values into individual variables while passing objects in as arguments.

To do this, we put what we want to assign the values, which is the stuff that’s on the left side of the destructuring assignment expression, as the parameter of the function.

So, if we want to destructure user into its parts as variables, we can write a function like the following:

const who = (`{`userName`,` name``: { firstName }}) => `${``userName`}'s first name is ${firstName}`;

who(user)

So, we get userName and firstName, which will be set as 'dsmith' and 'Dave' respectively as we applied the destructuring assignment syntax to the argument of the who function, which is the user object we defined before.

Likewise, we can set default parameters as with destructuring in parameters like we did with regular assignment expressions. So, we can write:

const who = (`{`userName = 'djones'`,` name``: { firstName }}) => `${``userName`}'s first name is ${firstName}``

If we have user set to:

let user = {
  id: 42,
  name: {
    firstName: 'Dave',
    lastName: 'Smith'
  }
};

Then we when call who(user), we get 'djones's first name is Dave' as we set 'djones' as the default value for userName.

We can use the destructuring assignment syntax when we are iterating through iterable objects. For example, we can write:

const people = [{
    firstName: 'Dave',
    lastName: 'Smith'
  },
  {
    firstName: 'Jane',
    lastName: 'Smith'
  },
  {
    firstName: 'Don',
    lastName: 'Smith'
  },
]

for (let {
    firstName,
    lastName
  } of people) {
  console.log(firstName, lastName);
}

We get:

Dave Smith
Jane Smith
Don Smith

Logged, as the destructuring syntax works in for...of loops because the variable after the let is the entry of the array.

Computed object properties can also be on the left side of the destructuring assignment expressions. So, we can have something like:

let key = 'a';
let {[key]: bar} = {a: 1};

This will set bar to 1 because [key] is set to a and then the JavaScript interpreter can match the keys on both sides and do the destructuring assignment to the variable bar.

This also means that the key on the left side does not have to be a valid property or variable name. However, the variable name after the colon on the left side has to be a valid property or variable name.

For instance, we can write:

`const obj = { 'abc 123': 1};
const { 'abc 123': abc123 } = obj;

console.log(abc123); //` 1

As long as the key name is the same on both sides, we can have any key in a string to do a destructuring assignment to variables.

Another thing to note is that the destructuring assignment is smart enough to look for the keys on the same level of the prototype chain, so if we have:

var obj = {a: 1};
obj.__proto__.b = 2;
const {a, b} = obj;

We still get a set to 1 and b set to 2 as the JavaScript interpreter looks for b in the prototype inheritance chain and sets the values given by the key b.

As we can see, the destructuring assignment is a very powerful syntax. It saves lots of time writing code to assign array entries to variables or object values into their own variables.

It also lets us swap variables without temporary variables and makes the code much simpler and less confusing. It also works through inheritance so the property does not have to be in the object itself, but works even if the property is in its prototypes.

const fn = () => {a:1, b:2}
const {a,b} = fn();