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.

Categories
JavaScript Best Practices

JavaScript Best Practices — Cases and Loops

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 case statements should be used and the best practices for writing loops.

Order Cases Alphabetically or Numerically

We may want to order our cases alphabetically or numerically to read them easier.

For instance, we can write:

switch (val) {
  case 1:
    //...
    break;
  case 2:
    //...
    break;
  default:
    //...
    break;
}

or write:

switch (val) {
  case 'a':
    //...
    break;
  case 'b':
    //...
    break;
  default:
    //...
    break;
}

Put the Normal Case First

If we put the normal case first, then we don’t have to go to the other cases as often because of short-circuiting.

So if we have the 'success' case as the normal case, we can write:

switch (val) {
  case 'success':
    //...
    break;
  case 'error':
    //...
    break;
  default:
    //...
    break;
}

Keep the Actions of Each Case Simple

Cases should be short to keep them readable. If the actions inside the case statement or block are complex, we should write functions to contain them.

For instance, we can write the following:

switch (val) {
  case 'success':
    handleSuccess();
    break;
  case 'error':
    handleError();
    break;
  default:
    //...
    break;
}

Don’t Make Up Phony Variables to be Able to Use the case Statement

A case statement should ve used for data that can easily be categorized.

Therefore, we should write something like:

const action = command[0];
switch (action) {
  case 'a':
    //...
    break;
  case 'b':
    //...
    break;
  default:
    //...
    break;
}

The variables that we pass into switch should be a simple variable. We shouldn’t have to do something like taking the first letter from a string before checking the cases.

The first letter can be used by more than one word, so we want to avoid using the first letter for our cases.

Use the default Clause Only to Detect Legitimate Defaults

default clause should only be used for real defaults.

If we don’t have a real default value, then we don’t need a default clause.

Use the default Clause to Detect Errors

If there’re cases that aren’t supposed to happen, we can use the default clause to catch those cases.

For instance, we can write something like:

switch (action) {
  case 'a':
    //...
    break;
  case 'b':
    //...
    break;
  default:
    handleError();
    break;
}

Then we handle errors in the default case in case it’s encountered.

Avoid Dropping Through the End of a case Statement

JavaScript doesn’t automatically break at the end of each case statement or block.

Therefore, we should write the break keyword to stop the execution at the end of the statement or block.

For example, instead of writing:

switch (action) {
  case 'a':
    //...
  case 'b':
    //...
}

We write:

switch (action) {
  case 'a':
    //...
    break;
  case 'b':
    //...
    break;
}

When to Use a while Loop

We should use while to test conditions for the exit at the beginning of the end of the loop.

To do that, we write:

while (!done) {
  if (condition) {
    done = true;
  }
  //...
}

This will check the condition at the beginning of the loop body.

We can also check at the end by moving the if block to the end.

Also, we have the do...while loop to run the loop body first before checking the condition for continuing the loop.

For instance, we can write:

do {
  if (condition) {
    done = true;
  }
  //...
}
while (!done)

Then the first iteration always runs.

Use a Loop-With-Exit Loop

We can also put a loop condition inside the middle of the loop body.

Then we can avoid errors that result from any invalid values that are produced before the exit check.

For instance, we can write:

while (!done) {
  //...
  if (length < 0 || width < 0) {
    done = true;
  }
  //...
}

Then if length or width are less than 0, we can avoid running the rest of the code that need them.

Conclusion

We can use the while loop to repeated run code and check for the condition in each iteration so we can end it.

There’s also the do...while loop to always run the first iteration before checking our condition.

If we use switch statements, we may want to order our case statements in order, and always have break at the end of the block.

Alternatively, we can also put the normal case first, and the error cases later.

Categories
JavaScript Best Practices

JavaScript Best Practices — With, Promise Errors, Regex Issues

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

In this article, we look at issues with the with statement, named capture groups, rejecting errors with Error object, and using regex literals instead of the RegExp object.

Remove with Statements

with statements are bad. They let us add member objects to the current scope, which makes it impossible to tell what the variable inside the block refers to.

For instance, if we have the following code:

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

with(obj) {
  a = 3;
}

Then the code is within the with block is written relative to the obj object. So a inside the block is actually referencing obj.a .

However, we can also declare new variables as follows:

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

with(obj) {
  let a = 3;
}

which is block-scoped and can’t be accessed outside the with block.

Or we can declare a variable with var as follows:

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

with(obj) {
  var a = 3;
}

which changes obj.a to 3.

As we can see the scope and of a varies depending on how we declared the variable inside with . We’re either modify the obj object’s properties or we’re declaring a new block-scoped variable if we use let or const .

Therefore, the with block is confusing and shouldn’t be used in our production code.

It doesn’t make writing our code easier, and it just makes our code more confusing to everyone.

Therefore, it should never be used in our code.

Use Named Capture Group in a Regular Expression

Named capture groups are good in regular expressions because it’s clear that where the capture groups are and what they’re checking for.

For instance, we can write something like the following:

const regex = /(?<email>[^@]+@[^.]+..+)/;

In the code above, we have a capture group called email that has the email regex after it.

Now instead of just having a bunch of symbols in our regex, we know that our regex capture group is checking for an email address.

Then we can retrieve the result of the capture group by using the exec method as follows:

const result = regex.exec('abc@abc.com').groups.email;

As we can see, the groups property of the object that’s returned by exec has the email property which has the match for our email capture group.

This is much better than just having a bunch of symbols without a name. We can’t get those with a named property.

Use Error Objects as Promise Rejection Reasons

Using error objects as promise rejection reasons is a good idea because it automatically stores the stack trace.

The stack trace is useful for debugging issues that caused the error since it tells us what functions are called to get to the final error.

If we don’t reject an error, then we have no stack trace and we don’t know what’s been called before the error.

For instance, instead of writing:

Promise.reject('error');

We should write:

Promise.reject(new Error('error'));

If we run both and look at the console log output, we’ll see that the 2nd example has the stack trace in the console log output and the first one doesn’t.

Use Regular Expressions Literals instead of the RegExp Constructor

In JavaScript, there’re 2 ways to construct regexes. One is the regular expression literals like /foo/ . The other way is to create an RegExp instance like new RegExp('foo');

Regular expressions are shorter and we can’t generate a regex dynamically with literals. The RegExp constructor takes a string with the regex that we want to create, so we can create a regex dynamically with a string.

However, if we want to add escape characters with the RegExp constructor, we’ve to add an extra backslash before the escape character so that we can write the escape character in the regex string as follows:

new RegEx('d+$');

Because of the extra complexity, it’s better to use regex literals instead of using the RegExp constructor. The regex above would be the same as:

/d+$/

if it’s written as a regex literal.

Conclusion

with statements should never be used in our code since it changes the scope of the variables inside.

Error objects should be used to reject promises so that we get a stack trace in our console log.

If we construct regexes, we should use the regex literals as it’s simpler. Named capture groups should be used so that we can retrieve the capture group match with a name and also makes the pattern easier to understand.