Categories
JavaScript Best Practices

JavaScript Best Practices — Variables

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 define and use variables in our JavaScript code.

Always Use const or let to Declare Variables

We should use let and const to declare variables and constants respectively.

This way, we get block-scoped variables and constants so we won’t run into issues with variables or constants being accessed in places that we won’t expect.

Without strict mode on, using let and const will also stop us from creating global variables.

Global variables pollute the global namespace and the more complex our code is, the more likely that our global variables will have the same name in different places. Then unexpected behavior will occur because of that.

const also prevents us from the reassignment of its value after it’s set. Both let and const prevents us from declaring a variable with the same name twice.

For instance, we can declare variables and constants with let and const as follows:

let a = 1;
const b = 2;

In the code above, we declared a variable a with let and a constant b .

Then we don’t have to worry about them being declared somewhere else or in the case of b , its value being reassigned to something else.

Use One const or let declaration Per Variable or Assignment

We should put each of our let and const declarations in their own line.

For instance, instead of writing the following code to declare multiple variables in one line:

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

We should instead put the const keyword in front of every declaration as follows:

const a = 1;
const b = 2;
const c = 3;

This way, we know that every line in the code above is declared with const . In the first example, we aren’t sure how they’re declared.

Also, it’s easier to swap variables that are in their own line since we can cut or copy and paste the whole line.

We can also step through each line with the debugger instead of looking at all the declarations at once.

Group All consts Declarations Together and Then Group All let Declarations Together

We should group all the const declarations together and then group all the let declarations together.

If we scatter them everywhere, then we’ll have a problem finding them later.

Also, we might need to assign a variable depending on one of the previously assigned variables.

For instance, if we have the following code:

const a = 1;
let foo;
const b = 2;
let bar;
const c = 3;

Then it’s hard to read and trace which variable is assigned to what. Instead, we should write the following:

const a = 1;
const b = 2;
const c = 3;

let foo;
let bar;

which is much more organized.

Photo by John Duncan on Unsplash

Assign Variables Where We Need Them But Place Them in a Reasonable Place

We should assign variables where we need since let and const variables are block-scoped and what those are the variables and constants that we should have.

Variables declared with var are function scoped and are hoisted so they can be accessed in places that we may not expect them to be accessed.

For instance, we should place our variables as follows:

const getGreeting = () => 'hi';

const greet = (name) => {
  if (!name) {
    return '';
  }

  const greeting = getGreeting();
  return `${greeting} ${name}`;
}

In the code above, we have the greeting constant inside our greet function. We put it there so we don’t have to run the getGreeting function unnecessarily.

We only run the getGreeting function when the name is a truthy value so that we don’t have to run it on every call.

Therefore, we didn’t place the code for the greeting declaration at the top line of or greet function as follows:

const getGreeting = () => 'hi';

const greet = (name) => {
  const greeting = getGreeting();
  if (!name) {
    return '';
  }

  return `${greeting} ${name}`;
}

It’s more efficient to declare variables and constants only when we need to use them.

Conclusion

When we declare variables, we should always use let or const to only declare block-scoped variables and constants.

const and let variables should be grouped in their own group. Also, they should be declared only when they’re needed.

Categories
JavaScript Best Practices

JavaScript Best Practices for Writing More Robust Code — Variables and Objects

JavaScript is an easy to learn programming language. It’s easy to write programs that run and does something. However, it’s hard to account for all the uses cases and write robust JavaScript code.

In this article, we’ll look at what JavaScript features should be used to write our JavaScript apps.

Writing Blocked-Scoped Code

Keeping all our code in blocks and variables inside it within the block’s scope is important because it reduces lots of confusion when people are reading code.

If everything is block-scoped, then we know that everything inside a block can only be accessed within the block. Therefore, it’s impossible for anyone to assign values to a block-scoped variable outside the block.

This means that we should never use var , we should always use strict mode, and we should always use let and const to declare variables and constants respectively.

let and const are both block-scoped, so that they’re only available in the block that they’re declared in.

For instance, we can create a code block with let and const variables and constants as follows:

if (foo){
 let x = 1;
}

In the code above, we have an if block with the variable declaration for x inside it.

When we try to reference it anywhere outside the if block, we’ll get an error since it’s not accessible outside the block. This rule never changes.

Unlike variables declared with var , there’s no hoisting, and it can’t be accessed outside the block.

var variables are accessible within the entire function, which is probably not what we want as it creates confusion on where we can reference it. Therefore, we shouldn’t use it.

Since ES2015, we can also define standalone code blocks in addition to if , switch , and functions.

This also limits the access of our variables and constants to that block if we use let and const to declare the variables and constants respectively.

For instance, we can do that as follows:

{
  let x = 1;
  const y = 2;
}

In the code above, we defined a block and then declared the x variable and y constant.

They can only be referenced inside the curly braces. This is much better than declaring a function and running it immediately since it’s less typing and we don’t have to declare another function unnecessarily.

const is different from let in that we can’t reassign something that’s declared with const . However, we can still modify the assigned object if we wish.

The Spread Operator

The spread operator, which is denoted by 3 periods, spreads array entries and object values to another array or object respectively.

This lets us create objects and arrays by merging one or more of them together.

We can also spread arrays into objects, which creates an object with the indexes of the original array as the keys and the corresponding entries as the values.

This is a quick and easy to understand method to merge multiple objects or arrays or make copies of them without writing any loops or anything more complex.

For instance, we can spread and object as follows:

const arr = [1, 2]
const obj = {
  ...arr
};

Then we get:

{
  "0": 1,
  "1": 2
}

as the value of obj as we expected.

Also, we can make a copy of an object as follows:

const obj = {
  a: 1
};
const copy = {
  ...obj
};

In the code above, we used the spread operator to make a shallow copy of obj by using the spread operator to spread the entries into the copy object.

Then we should see the same keys and values in both constants, but when we log obj === copy , we’ll see that the expression returns false since the spread operator creates a copy instead of referencing the original object.

The spread operator is also very handy for merging objects and arrays into one.

For objects, we can write the following to combine multiple object’s own properties into one object as follows:

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

In the code above, we merged obj1 and obj2 into a new object called merged using the spread operator. If 2 keys are the same, then the one that’s merged in later is kept.

Therefore, we see that merged is:

{
  "a": 3,
  "b": 2
}

We can also use that with arrays. All entries of the original array are kept. For instance, we can write:

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

Then merged is:

[
  1,
  2,
  3,
  4,
  5
]

The spread operator is a short, less error-prone, and easy to understand method to copy and merge objects and arrays, so it should be used for such purpose instead of writing anything more complex.

Conclusion

Some of the best JavaScript features that are released in the last few years are block-scoped variables and constants and the spread operator.

Block-scoped variables and constants reduces the chance of error by creating variables and constants that are always block-scoped, so it’s harder for values to be changed unintentionally.

The spread operator lets us copy and merge objects and arrays in a more reliable way.

Categories
JavaScript Best Practices

JavaScript Best Practices for Writing More Robust Code — Good and Bad Features

JavaScript is an easy to learn programming language. It’s easy to write programs that run and does something. However, it’s hard to account for all the uses cases and write robust JavaScript code.

In this article, we’ll look at some good features of JavaScript that we should use to write robust JavaScript code.

Use === Instead of ==

In JavaScript, there’s the === and == operators for determining the equality of 2 entities.

== coerces the type by following a long list of rules before doing the comparison between its 2 operands.

On the other hand, === doesn’t do any data type coercion before comparing its operands.

This makes === better since JavaScript’s data type coercion creates weird results that we don’t expect.

Using the == operator leads to expressions like 0 == false returning true .

We don’t want to make things a lot harder by saving one character on our code, so we should always use === to do equality comparisons.

Likewise, to check for inequality, we should use the !== operator, which also doesn’t do any data type coercion before comparing its operands for inequality.

Never Use Eval

eval lets us run code that’s embedded in a string. This means that theoretically, any user can run anything as long as they can set the value of the string that we pass into eval .

The code in eval runs in global scope so it can have a big impact if we let anything run with eval .

Therefore, we should avoid this at all costs. Also, it decreases our app’s performance since running code from a string means that the JavaScript interpreter can’t do any performance optimizations beforehand.

Never Use the Function Constructor

The Function constructor is like eval . It lets us define a function by passing in the code that we want to run inside the function.

For instance, we can pass in the parameter names and the function body as strings by writing the following:

const add = new Function('x', 'y', 'return x + y');

In the code above, we invoked the Function constructor with the 'x' and 'y' strings, which are the parameter names. Then we have 'return x + y' as the 3rd argument to return the sum of x and y .

We can then run our function as follows:

const sum = add(1, 2);

Like eval , we dynamically pass in strings to write our code. It also runs everything in the global scope and prevents optimizations just like eval does.

It also has the same security issues as eval since we still pass in strings to define our functions.

Therefore, we also shouldn’t use this to define our functions.

Don’t Pass in Strings as Code in setTimeout and setInterval

The setTimeout and setInterval functions allow us to run code after a delay and run code in a specified interval respectively.

One feature we shouldn’t use in either of them is passing strings into them to run code.

For instance, we shouldn’t write something like the following:

setTimeout('console.log("foo")', 100)

This will run console.log("foo") after 100 milliseconds, but we shouldn’t do this since again, we’re running code from a string which presents the same security and performance issues as the other occasions where we run code from a string.

Therefore, we should always run code that’s defined with code instead of a string, like the following:

setTimeout(() => console.log("foo"), 100)

The code above runs console.log like it does with the string, but the JavaScript interpreter can optimize the code and there’re no security issues since there’s no risk that attackers can inject code into our app as a string.

Always Add Semicolons and Parentheses

Semicolons should always be added to make our code as clear as possible. JavaScript can insert semicolons automatically when we don’t do it ourselves. Parentheses can also be optional with one-line if blocks.

It’ll insert it when it thinks it should be a new line, like in any logical break that it finds.

However, it often leads to confusion. If we write something like the following:

if (foo)  
  x = false  
  bar();

Then we may think that both lines are run if foo is true . But this isn’t the case.

The JavaScript interpreter will think that only x = false is part of the if block and bar() is separate.

Therefore, if we want to eliminate confusing code like this, we should write:

if (foo) {  
  x = false;  
  bar();  
}

to delimit our lines and blocks with semicolons and parentheses.

This way, we know that they both will run if foo is true .

Conclusion

=== and !== are always better than == and != for equality and inequality comparisons respectively.

Also, we should never run code from a string with eval , the Function constructor, setTimeout , setInterval or any other place that allows us to do that.

Finally, we should add semicolons and parentheses to delimit our code blocks.

Categories
JavaScript Best Practices

JavaScript Best Practices for Writing More Robust Code — Tools and Tests

JavaScript is an easy to learn programming language. It’s easy to write programs that run and does something. However, it’s hard to account for all the uses cases and write robust JavaScript code.

In this article, we’ll look at some tooling and testing best practices for writing robust JavaScript code.

Use TypeScript

TypeScript is a language that’s an extension of JavaScript to provide flexible and optional type checking for JavaScript code.

It builds code into JavaScript so that it can be run on the browser or in the Node.js environment.

The code is checked for type errors before the code is built into the final artifact. This means that data type errors, which would be runtime errors if it weren’t checked by TypeScript are prevented.

This is a big class of errors that are eliminated. The type checking isn’t rigid. It provides many ways to annotate the types of objects and return types of functions.

For instance, we can create interfaces to annotate the types of objects as follows:

interface Pet {
    name: string;
    walk(): void;
}

In the code above, we created an interface to indicate that whatever has the type Pet must have the name string property and a walk method that returns nothing (hence the void return type).

Then we can use that as follows:

const dog: Pet = {
    name: 'joe',
    walk() {
        console.log('walk');
    }
}

In the code above, we have the name string property and the walk method in the dog object, which meets the requirement of the interface.

Therefore, the code will build and run by the TypeScript compiler. We’ll get an error if the types of anything are different from the interface.

Another good feature of TypeScript is the flexibility of the type checking. The types don’t have to be fixed, they can be flexible and dynamic as well.

For instance, we can create nullable types as follows:

interface Pet {
    name: string;
    walk?(): void;
}

In the code above, the walk method has been made optional with the ? after the method name. Now we can omit it in any object that has type Pet .

We can also create union types of multiple types as follows:

interface Pet {
    name: string;
    walk(): void;
}

interface Animal {
    breed: string;
}

const dog: Pet | Animal = {
    name: 'joe',
    breed: 'labrador',
    walk(){}
}

In the code above, we have the Pet | Animal type, which consists of the members of the Pet and Animal types combined together.

Therefore, our dog object can have any member from each interface included in it.

Also, we don’t have to specify the types of an object directly. If we already have an object in our code and we want another object to have the same data type as that one, we can use the typeof operator as follows to specify the type:

const cat = {
    name: 'james'
}

const dog: typeof cat = {
    name: 'joe'
}

In the code above, we specified the data type of the dog object to be the same as the data type for cat with the typeof dog expression. This way, we don’t have to specify any types directly.

TypeScript has many more features that can help us write more solid JavaScript code by preventing data type errors that are otherwise caught at runtime.

This is especially important with big apps where there’s more chance of these errors happening.

Therefore, we should consider using TypeScript for writing more robust JavaScript code.

Photo by Jerry Wang on Unsplash

Write Tests

We should write automated tests to check for regressions in our code so that we can have peace of mind when changing code and all the automated tests pass.

It’s easy to write automated tests with the Jest test runner, which has many features to let us write and run tests for both front and back end JavaScript apps.

For instance, we can write a simple function with unit test as follows:

math.js :

const multiply = (a, b) => {
  return a * b;
}
module.exports = {
  multiply
};

math.test.js :

const math = require('./math');

test('multiplies 1 * 2 to equal 2', () => {
  expect(math.multiply(1, 2)).toBe(2);
});

In the code above, the math.js module has the function multiply that we want to test.

Then in math.test.js , we added our test for testing the multiply function exported by math.js .

The file names are the convention for Jest tests, where we have the name of the production code file corresponds with the name of the test file.

Then when we run Jest, this test will run and should pass because 1 times 2 is 2.

If we write unit tests for every part of our app then it’s easy to know whether our app is still working properly.

Conclusion

TypeScript is probably the best type checker for JavaScript. It’s a natural extension of JavaScript to add type annotations and checking to our JavaScript code.

Writing automated tests is always a good idea so that we can check that our code is working properly after we make changes to it.

Categories
JavaScript Best Practices

JavaScript Best Practices — Code That We Shouldn’t Have

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 some code that we shouldn’t add to our JavaScript codebase.

No Unnecessary Labels

JavaScript has labels that we can label parts of our code. For instance, if we have 2 loops, we can label them as follows:

A: while (a) {
  break A;
}

B: while (b) {
  break B;
}

In the code above, we have label A to label the first while loop and B to label the second while loop.

However, the example above is useless because the label is just referenced within itself. So the code above is the same as:

while (a) {
  break;
}

while (b) {
  break;
}

Therefore, the labels are useless.

We should use labels to only reference other pieces of code which the label is used to label. For instance, we can write the following code:

A: while (a) {
  break B;
}

B: while (b) {
  break A;
}

No Case Statement Fallthrough

In switch blocks, we can write case statements or blocks without the break keyword at the end of each case .

This isn’t good because all the case statements or blocks will run even if a matching case is found within the switch statement.

For instance, if we have:

let foo = 1;
let bar;
switch (foo) {
  case 1:
    bar = 'x';
  case 2:
    bar = 'y';
}

Then we’ll see that bar is 'y' even though foo is 1, which is probably not what we want.

The correct way to write the switch statement is to write the following:

let foo = 1;
let bar;
switch (foo) {
  case 1:
    bar = 'x';
    break;
  case 2:
    bar = 'y';
    break;
}

Then bar will be 'x' as we expected. Alternatively, we can also write return instead of break as follows:

let foo = 1;
const baz = (foo) => {
  switch (foo) {
    case 1:
      return 'x';
    case 2:
      return 'y';
  }
}

let bar = baz(foo);

In the code above, we have return statements instead of break, and we placed the switch statement in the function so we can get the return value when calling it.

It’ll give us the same result as using break since it ends the code execution of the function.

No Floating Decimals

Floating decimals can be before or after a number in JavaScript. For instance, we can write the following:

let num1 = .1;
let num2 = 3.;
let num3 = -.5;

In the code above, we defined numbers with decimal points before or after a number.

This isn’t good because it’s not clear that the dot is for the dot operator for accessing properties or whether it’s a decimal point.

Instead, we should just put in the leading and trailing zeroes as follows:

let num1 = 0.1;
let num2 = 3.0;
let num3 = -0.5;

Photo by Vladislav Klapin on Unsplash

Assignment to Native Objects or Read-Only Global Variables

Read-only global variables like window or Object are read-only. Therefore, we shouldn’t be assigning new values to it.

For instance, we don’t want to do things like:

window = {};

since we don’t want window to be an empty object. Other things we don’t want include code like:

Object = null;
undefined = 1;
null = 2;

JavaScript strict mode should prevent these assignments from happening. If we didn’t use strict mode, then we should make sure that we don’t do things like this.

Modules are automatically set to use strict mode, so we don’t have to worry about this.

No Type Conversion with Shorter Notations

We can use the unary + , - , or ~ to convert values to numbers or boolean.

They aren’t very clear to some people, so we may want to limit their use. Therefore, instead of writing:

let b = !!foo;
let c = +'2';

We should convert them explicitly with built-in JavaScript functions as follows:

let b = Boolean(foo);
let c = Number('2');

Conclusion

We shouldn’t write code that is useless or don’t do what we expect them to. For instance, case statements and blocks in switch statements should always have break or return added.

Decimals should either not be used or we add leading and trailing zeroes to make it clear.

Also, we should never assign native global objects with our own values.

Finally, we may want to convert data types explicitly with our own code to make our type conversion code more clear.