Categories
JavaScript Best Practices

JavaScript Best Practices — Destructuring

JavaScript is a very forgiving language. It’s easy to write code that runs but has mistakes in it.

In this article, we’ll look at how to use the JavaScript destructuring syntax to our advantage.

Use Object Destructuring When Accessing and Using Multiple Properties of an Object

The destructuring syntax is great for setting multiple object properties to variables at the same time.

It saves us from creating temporary references to those properties.

For instance, instead of writing the following to assign our object properties to variable the old way:

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

const a = obj.a;
const b = obj.b;

We can write the following:

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

const {
  a,
  b
} = obj;

In the code above, we set the obj.a ‘s value to a and obj.b ‘s value to b with the destructuring syntax. It’s the same as the old way, which requires us to access the object properties individually.

The benefit is that we don’t have to reference obj in every line.

In both examples, we have the value of a being 1 and the value of b being 2.

It also works with function arguments. For instance, we can destructure object parameters into variables by writing the following:

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

const add = ({
  a,
  b
}) => a + b;
const sum = add(obj);

In the code above, we have the same obj object with properties a and b . We also have the add function, which takes an object with properties a and b and returns the sum of them.

We then pass in obj as an argument of add . The destructuring syntax will then take the value of property a and set it as the value of parameter a and do the same for b .

Therefore, we get 3 as the return value in the example above.

Furthermore, we can do the same thing for objects in arrays. If we use the for...of loop, then we can use the object destructuring syntax as follows:

const arr = [{
    name: 'jane',
    age: 20
  },
  {
    name: 'joe',
    age: 22
  },
];

for (const {
    name,
    age
  } of arr) {
  console.log(name, age);
}

In the code above, we destructured our object in the first line of our for...of loop. We destructured the name and age properties of each entry of arr into the name and age loop variables is updated in each iteration.

Use Array Destructuring

Like with object destructuring, we can destructure arrays the same way. For instance, we can use it as follows:

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

In the code above, we set the variable values by the position that they’re in. So a is set to 1 and b is set to 2.

This is much better than assigning them to variables the old way, which is the following:

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

As we can see, we’ve to write 3 lines to do the same thing. Plus we have to set a name for the array before getting the entries and assigning them to variables.

We didn’t have to do that with the destructuring syntax.

Likewise, we can do the destructure arrays in parameters. For instance, we can write the following code:

const add = ([a, b]) => a + b;
const sum = add([1, 2]);

In the code above, we destructured our array parameter in the add function into variables and return them added together.

Then we can call add with an array in the 2nd line to get the sum of them.

We can also use the syntax in the for...of loop as follows:

const arr = [
  ['a', 1], ['b', 2]
];
for (const [key, val] of arr) {
  console.log(key, val);
}

In the code above, we destructured our array entries in the for...of loop much like how we did it with the object destructuring syntax, so we get:

a 1
b 2

logged in the console.

Conclusion

The destructuring is great for destructuring objects and arrays. We can use it to destructure object property values into individual variables by matching their position and the identifier name.

With arrays, the destructuring is done by matching the position of the array entry with the position of the variable.

Categories
JavaScript Best Practices

JavaScript Best Practices — Variable Scopes

JavaScript is a very forgiving language. It’s easy to write code that runs but has issues in it.

In this article, we’ll look at best practices for declaring variables and using JavaScript variable scopes.

Scope

The scope is where we can access a variable.

JavaScript has several kinds of scopes. Variables declared with var has function scope, and variables declared with let or const has block scope.

var variables can also be hoisted so that the variable can be accessed before it’s defined.

let and const variables and constants aren’t hoisted.

Localize References to Variables

Variables are all local in JavaScript if they’re declared with keywords.

If they’re not, then they’re global. Global variables can only be declared in strict mode.

If it’s on, then we can’t declare them.

Global variables are declared with no keyword.

Therefore, we should stick with let and const for declaring variables and constants.

Keep Variables “Live” for as Short a Time as Possible

We should keep them available for as short a time as possible. This means the lines of code that the variable is available for referencing should be small.

This way, we can’t accidentally assign them to an unexpected value as easily and reduce the chance of errors.

If a variable is only available within the block, then that’s better than having it available outside a block.

That’s another benefit to using let and const since they’re block-scoped and we can be sure that they can’t be referenced before they’re defined.

Also, they won’t be available to any code outside the block.

Short live times make our code more readable since we don’t have to keep so much in our minds.

The chance of initialization errors would be reduced.

We can also split block-scoped variables into smaller functions easily.

General Guidelines for Minimizing Scope

We can minimize the scope of our variables easily.

There’re a few guidelines for minimizing scope below.

Initialize Variables Used in a Loop Immediately Before the Loop

We should declare variables used in a loop immediately before the loop so that we can see where they’re used right away.

If we modify the loop, we’ll remember that the variable is used and we won’t make mistakes with them.

For instance, we can write:

let done = false;  
while (!done) {  
  //...  
}

We have the done variable right before the while loop, so we won’t forget about it when we’re working on the loop.

Don’t Assign a Value to a Variable Until Just Before the Value is Used

The values of a variable shouldn’t be assigned until right before the value is used.

This way, it’s clear where the variable first receives its value, and confusion is minimized.

Group Related Statements

If we have related statements, then we should group them together.

This way, we don’t have to jump back and forth when we ready our code to get the whole workflow.

Break Groups of Related Statements into Separate Functions

Shorter functions have shorter variable spans, which is good for readability.

The scope of variables is reduced so that we don’t have to scroll to read all the places where a variable is accessed.

Begin with Most Restricted Visibility, and Expand the Variable’s Scope Only if Necessary

Block scoped variables is good for restricting visibility. It confines the variables within the block.

We should only expand the scope if we need to since we don’t want to expand the ‘live’ time to minimize the chance of assigning them accidentally and make them harder to read.

Minimizing Scope

Maximizing scope by expanding variable scopes may make them easier to write, but the program is easier to understand since those variables may be referenced anywhere.

That’s not good since we don’t want to do that.

We’ve to look at where all the variables in all places just to understand how one variable is used, which is very bad for readability.

Therefore, minimizing scope is definitely something that we should do.

Conclusion

We should minimize the scope of our variables to make them easier to read.

Variables with smaller scopes can also be moved around easier so that we won’t have a difficult time looking at them at all the places that they’re used.

Therefore, block scope variables and constants are good. We can declare them with let and const respectively.

Categories
JavaScript Best Practices

JavaScript Best Practices — Renaming Imports and Proper Variable Declaration

JavaScript is a very forgiving language. It’s easy to write code that runs but has mistakes in it.

In this article, we’ll look at the proper way to rename imports and how to declare JavaScript variables properly.

No Renaming Import, Export, and Destructured Assignments to the Same Name

In JavaScript, we can rename our imported members and members that are exported with the as keyword.

Likewise, we can rename destructured assignments variable to the name that we want with the colon and the name we want after it.

For instance, we can rename an imported member as follows:

import { foo as bar } from "./module";

In the code above, we imported the foo member from module.js and then renamed it to bar in the current module by using the as keyword as we did above.

Then we can reference bar instead of foo in the current module.

We can also do the same thing for exports. For instance, we can write the following to export a member with a different name than it’s defined as.

To do that, we can write the following:

module.js

const foo = 1;
export { foo as bar };

index.js

import { bar } from "./module";

In the code above, we defined the constant foo in module.js and exported it as bar by using the as keyword in our export statement.

This lets us rename our exports before it’s exported.

We can also rename destructured assignments as by writing the following code:

const {
  foo: bar
} = {
  foo: 1
};

In the code above, we renamed our destructured foo property to bar by writing:

{
  foo: bar
}

Then the JavaScript will pick up the foo property from the right side and then set its value as the value of bar so that we reference it with bar instead of foo .

This is a convenient way to destructure object properties to variables and also rename them with the variable name that we want.

However, with these syntactic sugars, we can use them in useless ways by renaming them to the same name as they’re originally defined.

For instance, with imports, we can write the following code:

import { foo as foo } from "./module";

With exports, we can write something like:

const foo = 1;
export { foo as foo };

And with destructuring syntax, we can write:

const {
  foo: foo
} = {
  foo: 1
};

Since we renamed the variable to the same name as before, the renaming code is useless.

Therefore, we should remove them.

For imports, we just write:

import { foo } from "./module";

We can rewrite our export code as follows:

export const foo = 1;

And with destructuring, we can write:

const {
  foo
} = {
  foo: 1
};

Use let or const Instead of var to Declare Variables and Constants

In modern versions of JavaScript, there’s a right way to declare variables and constants.

We should eliminate anything that’s declared with var and use let or const instead.

With var the variables declared with it are function scoped and are hoisted, leading to lots of confusion among developers.

We don’t want lots of confusing in are code that is caused by that.

For instance, with var , our code can be accessed outside blocks. For instance, we can define and access a variable as follows:

const foo = () => {
  if (true) {
    var x = 1;
  }
  console.log(x);
}

foo();

In the code above, we’ll see that the console log outputs 1 because x is available outside the block since it’s declared with var .

Also, we can reference x before it’s defined because of hoisting, so if we have:

const foo = () => {
  console.log(x);
  if (true) {
    var x = 1;
  }
}

Then logging x will log undefined since we logged x ‘s value before it’s defined.

This is confusing to lots of people, and so since ES6, we have the let and const keywords to declare variables and constants respectively.

let and const are block-scoped so that variables and constants declared with them can’t be accessed outside blocks.

For instance, the following will give us an error because we tried to access the variable outside the block:

const foo = () => {
  console.log(x);
  if (true) {
    let x = 1;
  }
}

The following will also give us an error:

const foo = () => {
  if (true) {
    let x = 1;
  }
  console.log(x);
}

We can only access x inside the if block as follows:

const foo = () => {
  if (true) {
    let x = 1;
    console.log(x);
  }
}

With const , we can declare constants, which means that they can’t be reassigned to a new value. It’s also block-scoped like let .

When we declare variables with let and const , there’s no confusion.

Conclusion

We shouldn’t rename imports, exports, and destructured assignments to the same as it was before since it’s useless.

Also, let and const should be used to declare variables and constants respectively instead of var .

Categories
JavaScript Best Practices

JavaScript Best Practices- Parsing Numbers, Promises, Unicode and Regex

JavaScript is a very forgiving language. It’s easy to write code that runs but has mistakes in it.

In this article, we’ll look at ways to parse number better, requiring await in async functions, and adding a Unicode flag to our regex.

Add a Radix Argument When Calling parseInt

The JavaScript parseInt function takes a 2nd argument that has the radix of the number being parsed. The radix is the 0x prefix of the number.

Before ES5, parsseInt autodetected octal literals, which makes anything with a 0 before it is parsed as an octal number instead of a decimal number.

However, ES5 or later changed this behavior and now numbers with a leading 0 are parsed as a decimal number.

But it’s still a good idea to explicitly specify the parseInt function so that everyone knows what kind of number do we want to parse the number string to.

For instance, instead of writing the following code:

const num = parseInt("021");

We should write the following code:

const num = parseInt("021", 10);

The 10 in the 2nd argument makes sure that parseInt parses '021' as a decimal number so that it or any developer won’t be confused with what it’s parsed as.

Therefore num is 21.

We can also specify that it’s parsed as an octal literal as follows:

const num = parseInt("021", 8);

Then num is 17 since octal 021 is 17 as a decimal number.

No async Functions Which Have No await Expression

In JavaScript, an async function is one that has a chain of promises inside and only returns a promise.

An async function without any await expressions in it just return a promise with whatever we put after the return statement or a promise that resolves to undefined if we didn’t return anything inside.

There’s no point in having async functions that have no await expressions inside since we either aren’t running any promise code inside it or that we forgot the await before the promise so that they won’t be chained properly.

Either way, we should rectify these situations. If it’s just synchronous code, then we don’t need to put them inside an async function.

If we forgot to resolve the promises with await , then we should put await in front of the promises.

Therefore, we shouldn’t have code like:

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

Instead, we write something like:

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

The code above is an async function to call an API, which is a common use of promises.

In the end, it returns the data that’s obtained from the API.

If we throw an error, in an async function as follows:

const error = async () => {  
  throw new Error("error");  
}

We can replace the code above with:

const error = () => Promise.reject(new Error("error"))

They both return promises which are rejected with an Error instance.

Use of u flag on Regex

With the u flag added to the end of our regex, we can properly parse UTF-16 characters, which includes characters like emojis and other characters in an extended character set.

It also makes syntax errors be thrown so that we’ll know about them. Without the u flag, syntax errors won’t be thrown if we have them in our regex.

Therefore, it lets is find errors early on instead of when we’re running code that’s after the regex is defined.

So, instead of writing code like the following:

const a = /foo/;  
const b = new RegExp('foo');

We should write the following:

const a = /foo/u;  
const b = new RegExp('foo', 'u');

Conclusion

The radix argument should be added when we call parseInt so that it’ll always be parsed in as the kind of number that we want.

It also eliminates any ambiguity when it comes to what kind of number is returned from parseInt .

Async functions that have no await expressions in it probably don’t need to be inside an async function.

The u flag should be added after a regex literal or object so that we can see syntax errors with our regex earlier and also checks for characters in the UTF-16 character set properly.

Categories
JavaScript Best Practices

JavaScript Best Practices — More About Arrays

JavaScript is a very forgiving language. It’s easy to write code that runs but has mistakes in it.

In this article, we’ll look at the best ways to manipulate array entries with JavaScript.

Use Array.from Instead of The Spread Operator for Mapping over Iterables

The Array.from method lets us convert an iterable object into an array. Also, it lets us map the iterable object’s values without creating an intermediate array.

Therefore, we should use it instead of the spread operator and map together to map an iterable object to a new array.

For instance, we can use it as follows:

const obj = {
  0: 1,
  1: 2,
  length: 2
}
const arr = Array.from(obj, (a) => a * 2);

In the code above, we have an object obj which has the entries with integer keys and the length property, so we can convert it to an array with the Array.from method.

We can map the entries by passing in a callback to map the entries into something that we want as the 2nd argument.

This way, we don’t have to use the spread operator to convert an iterable object into an array and then call map on it as follows:

function* foo() {
  yield 1;
  yield 2;
}
const arr = [...foo()].map((a) => a * 2);

In the code above, we defined a generator function and then called it to convert the returned entries into an array. Then we called map to map it into the entries that we want.

This isn’t as good because we have to create an array and then call map on it.

Use Return Statements in Array Method Callbacks Except for Single Line Arrow Functions

We should always return something on our array method callbacks except when we define a callback for forEach or in single line arrow functions, which returns things implicitly.

For instance, we should write the following to call map with a callback that returns something:

const arr = [1, 2].map((a) => a * 2);

In the code above, our callback is (a) => a * 2 which returns a * 2 .

Also, we can write that as follows:

const arr = [1, 2].map((a) => {
  return a * 2;
});

This way, the return statement is clearer.

We shouldn’t write something like the following:

const arr = [];
[1, 2].map((a) => {
  arr.push(a * 2);
});

In the code above, the callback didn’t return anything. Instead, it just calls push on the arr array which is outside the callback. It creates a side effect and doesn’t return anything, which is both bad.

We should just make it return something in our callback like the map method expects us to.

Use Line Breaks After Open and Before Close Array Brackets If an Array Has Multiple Lines

If an array entry has multiple lines, then we should add a line break after the opening bracket and before the closing bracket to separate the entries from the brackets.

This improves the readability of our array entries since we know where they start and end.

For instance, we can write the following code to do that:

const arr = [
  {
    a: 1
  },
  {
    b: 2
  }
]

In the code above, we have an array with objects and we have line breaks before the first and after the last entry of the array to make the entries easier to read.

If we can write everything in one line, then we don’t need line breaks in our array code to separate the entries and the brackets.

For instance, we can write the following:

const arr = [1, 2, 3];

In the code above, we just kept everything in one line since each entry is so short that we can write the whole array in one line.

Conclusion

The Array.from method is good for converting iterable and non-iterable array-like objects into arrays and mapping each entry to new values at the same time.

This is good because we don’t have to create an intermediate array and the calling map on it like we have to do with the spread operator.

If our array entries are long, then we should write out all of them in their own line.