Categories
JavaScript Best Practices

JavaScript Best Practices — Formatting Lines

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 practices for layout code with blocks and lines.

Make the Incompleteness of a Statement Obvious

If statements have to be broken across lines, then we should make that obvious.

For instance, we write:

str.incluees('a') &&
str.incluees('z') &&
str.incluees(0) &&
str.incluees(9)

Now we know that the expression continues to the next line since we have && at the of the line.

Keep Closely Related Elements Together

Related elements should be kept together to let us follow the code more easily.

For instance, instead of writing:

const name = person['firstName'] + ' ' + person[
  'lastName'
]

we write:

const name = person['firstName'] + ' ' +
  person['lastName']

so that we can have the object property access code in the same line.

Indent Function-Call Continuation Lines the Standard Amount

If we’re calling a function, we should indent all long expressions by the same amount.

2 spaces are also pretty standard for indenting argument expressions, so we can write:

fn(
  'foo',
  'bar'
)

Make it Easy to Find the End of a Continuation Line

Having each argument on their own line is also a good idea to make the arguments more readable.

So we may want to put them in their own line, especially if they’re long.

Indent Control-Statement Continuation Lines the Standard Amount

Conditionals and loops should also be indented the same amount.

For instance, we should write:

while (!done) {
  //...
  doSomething();
}

for loops. We have 2 spaces to indent the body.

For conditional statements, we write:

if (!done) {
  //...
  doSomething();
}

Which has the same indentation as the loops.

Do not Align Right Sides of Assignment Statements

We shouldn’t align the right sides of the assignment statements.

For instance, we shouldn’t write:

bill      = bill + purchases;
totalBill = bill + previousBalance( customerID ) +
     lateCharge( customerID );

It just takes extra effort and doesn’t improve readability that much.

We should just let our code formatter decide on the alignment, so we write:

bill = bill + purchases;
totalBill = bill + previousBalance(customerID) +
  lateCharge(customerID);

Using Only One Statement Per Line

Only one statement per line makes sense for readability. Shorter lines are more readable.

So instead of writing:

let i = 0, j = 0, k = 0; destroy(i, j, k);

We write:

let i = 0,
  j = 0,
  k = 0;
destroy(i, j, k);

In addition to better readability, it also provides a more accurate view of our program’s complexity.

Putting several statements in one line also doesn’t provide optimization clues to compilers.

We can also follow the left margin of the code to following it line by line

Syntax errors are also easier to find if everything is on their own line.

Individual statements can also be edited or deleted more easily if they’re on their own line.

Use Only One Data Declaration Per Line

We should declare variables and constants on their own line.

For instance, we can write the following:

let i = 0;
let j = 0;
const k = 0;

This makes each declaration clear. We can also see what kind of data they are.

Declare Variables Close to Where They’re First Used

Variables should be declared close to where they’re first used.

It’s better to declare close to where they’re first used to avoid accidental assignments and group related code together.

It’s also easier to follow how variables are used if they’re only used in a few lines apart.

Order Declarations Sensibly

Grouping declarations by type makes sense since they’re grouped logically.

It’s easier to read logically related things.

Indent a Comment with its Corresponding Code

If we have comments, they should be indented the same way as code.

For instance, if we have a loop, we write:

while (!done) {
  // comment
  doSomething();
}

Conclusion

We should only have one statement per line to make them easier to read.

Also, we shouldn’t align the right side of assignment statements since it’s just extra effort for not much reward.

Indentation should be consistent with code and comments.

Categories
JavaScript Best Practices

JavaScript Best Practices — Compound Statements

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 practices for writing compound statements with JavaScript.

Write Pairs of Braces Together

It’s easy to forget braces when we’re writing blocks.

Therefore, we may want to write the braces first and then fill in the statements next.

For instance, we first write:

if (i < maxLines)

Then we write:

if (i < maxLines){}

Then we fill in the statements inside:

if (i < maxLines){
  // do something
}

Use Braces to Clarify Conditionals

We should add braces in conditional blocks to clarify them.

Even though JavaScript lets us write single line conditional statements without braces, we can put in the braces:

if (denominator !== 0) {
  result = a / denominator;
}

Dangerously Deep Nesting

Nesting is bad since they’re hard to read. And changing hard to read code increase the chance of making bugs.

Therefore, we should reduce or eliminate nesting as much as possible.

If we have:

if (foo) {
  //...
  if (bar) {
    //...
    if (qux) {
      //...
      if (baz) {
        //...
      }
    }
  }
}

Then we should rewrite it to eliminate the nesting.

Simplify a Nested if by Using a break Block

If we have nested in loops, we may be able to eliminate them with break statements.

For instance, we can write the following:

while (condition) {
  if (shouldEnd) {
    break;
  }
  //...
}

And we end the loop when shouldEnd is true .

We can add break blocks for any condition that should end the loop.

Convert a Nested if to a Set of if-else Blocks

If we have nested if statements, we can eliminate them by turning into if...else blocks.

For instance, if we have:

if (10 < subtotal) {
  if (100 < subtotal) {
    if (1000 < subtotal) {
      total *= 0.9;
    } else {
      total *= 0.8;
    }
  } else {
    total *= 0.7;
  }
}

Then we should restructure it in a cleaner way by removing the nesting by writing:

if (10 < subtotal) {
  total *= 0.7;
} else if (100 < subtotal) {
  total *= 0.8;
} else if (1000 < subtotal) {
  total *= 0.9;
}

It’s just much easier to read without the nesting.

Convert a Nested if to a case Statement

We can also convert nested if statement to switch statements.

For instance, we can write:

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

There’s no nesting, so it’s easy to read and we can see all the conditions.

Factor Deeply Nested Code into its Own Function

Moving deeply nested code into its own function will reduce the nesting, so we should do that.

It also makes each part shorter, so that’s even better.

Use a More Object-Oriented Approach

Instead of writing out long procedures that have lots of similar code and nesting, we can use classes and objects to encapsulate them into one package and use them instead.

This way, we can create similar objects that do similar things instead of writing them all out line by line.

Redesign Deeply Nested Code

Deeply nested code should be redesigned to reduce nesting.

It’s too complex and it hurts people’s brains to read them. Changing them will be error-prone.

Reducing Complexity

Reducing complexity will make our lives easier.

No one likes to be overwhelmed with complex things.

We can measure the complexity of a piece of code by counting the number of straight paths.

Then we add that by the number of if , while , for , && and || .

Then we add that total by the number of case statements or blocks.

The higher the total, the more complex the code is.

Conclusion

Reducing complexity will make our lives easier.

We can do that by counting the branches and straight-line code a group of code has.

Also, nesting is always hard on our brains, so we can move them to functions or classes.

We can write braces first so that we won’t forget them when we define functions.

Categories
JavaScript Best Practices

JavaScript Best Practices- Variable Declarations

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 declare variables the right way.

Require Initialization in Variable Declarations

Variable declarations should have values assigned to it when it’s declared so that we don’t have to worry about undeclared variables later.

For instance, we should write the following code:

var x = 1;

to make sure that x has value from the beginning.

Also, constants declared with const must be declared with a value, so we must write:

const x = 1;

However, this is more of a stylistic preference since it doesn’t have a significant impact on our code.

Never Use the delete Operator on Variables

The delete operator should never be used on variables. It might lead to unexpected behavior.

For instance, if we have the following code without strict mode on:

let x = 1;
delete x;

We get that x is still 1 after using the delete operator on it. It also prohibited if we use strict mode, so the following code will throw an error:

'use strict'
let x = 1;
delete x;

The code above will give us the error ‘Uncaught SyntaxError: Delete of an unqualified identifier in strict mode.’

This is one good reason to use strict mode is to prevent us from doing things like using delete on variables.

Don’t Name Labels With the Same Name as Variables Names

We shouldn’t have label names to label loops with names that are the same as variable names.

For instance, we shouldn’t have labels as we have in the following code:

let x = 1;

const baz = () => {
  x: for (let y = 0; y <= 1; y++) {
    break x;
  }
}

It’s just confusing to have labels that have the same name as a variable.

No Undeclared Variables

Undeclared variables are variables that haven’t been defined.

Without strict mode, these would just be created on the fly as global variables. This isn’t desirable as it pollutes the global scope. We don’t want that because multiple global variables with the same name may conflict with each other.

Therefore, we shouldn’t have code like the following:

a = 1;

In the code above, if strict mode isn’t on, then a is declared as a global variable.

We don’t want that, so we should turn on strict mode, which prevents the creation of the global variable a and instead will throw an error.

To declare variables, we should either use let , const , or var . let and const are much preferred because they’re block-scoped and they can’t be referenced before they’re declared. const also can’t be reassigned to a new value, and a value must be set when something is declared with const .

Also, we should use undeclared variables with typeof . For instance, if a is undeclared, we should write expressions like:

typeof a === 'undefined';

Without strict mode, the expression above will return true if a isn’t declared beforehand.

With strict mode on, as follows:

'use strict';
typeof a === 'undefined';

it’ll also return true , so we should check that we don’t have these kinds of undeclared variables used with the typeof operator.

No Initializing to undefined

In JavaScript, variables that are declared and not initialized is automatically set to undefined . Therefore, we don’t have to set it to undefined explicitly.

For instance, we don’t have to write something like the following to set bar to undefined :

let bar = undefined;

Instead, we can just write:

let bar;

Don’t Use undefined as a Variable Name

We shouldn’t use undefined as a variable name since it’s reserved keyword.

For instance, we should never write something like the following:

var `undefined = "hi";`

Without strict mode, this would just do nothing. If we log undefined after this line, we’ll still get undefined .

However, this is useless and confusing. Therefore, it’s prohibited with strict mode on.

We also can’t replace var with let or const as follows:

let undefined = "hi";

or:

const undefined = "hi";

As we’ll get the error ‘Uncaught SyntaxError: Identifier ‘undefined’ has already been declared’.

This is another good reason to use let and const .

Conclusion

We should be careful when we’re declaring JavaScript variables. We shouldn’t declare variables with reserved keywords like undefined .

Also, we shouldn’t have undeclared variables in our code. JavaScript strict mode should prohibit this from happening.

delete operator shouldn’t be used on variables since it doesn’t do anything.

Labels shouldn’t have the same name as variable names to eliminate confusion.

Categories
JavaScript Best Practices

JavaScript Best Practices — Strings, Booleans and Constants

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 how we should work with strings, booleans, and constants in JavaScript.

Avoid Magic Strings

Just like magic numbers, magic strings are just as bad.

If we have the same string used in multiple places without explicitly stating the meaning, then we should assign the value to a named constant.

For instance, if we use the string 'employee' everywhere, then we should explicitly assign it to a constant.

We can assign it by writing;

const WORKER_TYPE = 'employee';

so that we know that it’s referring to the type of worker in a company.

Also, changing it would be easier since we only have to change it once rather than in many places.

We may also decide to make our program international. Then this can let us translate it easily.

Watch for Off-by-One Errors

We should watch for the index of a string so that we won’t try to access an index beyond the length of the string minus 1.

Check How Our Language and Environment Support Unicode

If we work with Unicode characters, then we’ve to check if our language or environment actually supports it.

JavaScript programs should support Unicode in most cases, but we still have to check.

Decide on an Internationalization/Localization Strategy Early in the Lifetime of a Program

Internationalization and localization are major issues.

If we have to translate and localize our program, then it’s going to be a lot of working doing the translations and making everything act right in all the supported languages.

If we Need to Support Multiple Languages, Use Unicode

Unicode supports many languages ut of the box.

Use Boolean Variables to Document Our Program

We can assign boolean expressions to a variable so that we know what the expression is testing.

For instance, instead of writing:

navigator.userAgent.toLowerCase().indexOf('mac') !== -1

We can assign that to a variable by writing:

const isMac = navigator.userAgent.toLowerCase().indexOf('mac') !== -1;

Then we know that we’re checking for Mac users on our website.

Use Boolean Variables to Simplify complicated Tests

If we have complex tests, then we can also assign the expressions to variables so that we can see them easily.

For instance, if we have:

!error && MIN_COUNT < lineCount && lineCount < MAX_COUNT

We can define a variable to store that as follows:

const successfullyReadFile = !error && MIN_COUNT < lineCount && lineCount < MAX_COUNT

Now we know that those expressions together are for checking whether we read a file successfully or not.

Simulate Enumerated Types

Enum types are great for setting variables that can take on a few possible choices.

However, JavaScript doesn’t have an enum type.

However, we can simulate that with static variables of a class as follows:

class Colors {}
Colors.RED = 'red';
Colors.GREEN = 'green';
Colors.BLUE = 'blue';

We can also put the choices in an object:

const Colors = {
  RED: 'red',
  GREEN: 'green',
  BLUE: 'blue',
}

Then we can use them as follows:

const color = Colors.RED;

Use Named Constants in Data Declarations

Named constants are great for data declarations.

If there’re values that we don’t change and use in many places, then we should assign them to a named constant.

For instance, we can write:

const MAX_DONUTS = 10;

to set the maximum amount of donuts someone can eat.

Avoid Literals

It’s similar to the advice of the previous section. If we have literals that don’t have an obvious meaning, then we should assign them to a named constant.

For instance, if we have:

for (let i = 0; i < 10; i++) {
  //...
}

We have 10 that we don’t know the meaning of.

So instead, we write:

const MAX_DONUTS = 10;
for (let i = 0; i < MAX_DONUTS; i++) {
  //...
}

so that we know 10 is the maximum number of donuts.

Use Named Constants Consistently

We should use name constants consistently rather than using constants in some places and literals in others.

This way, we won’t forget to update values in some places if we need to.

Conclusion

We should avoid any magic strings and use named constants instead. This way, we’ll only have to change one place if the constant value needs to be changed.

They also make reading the code easier since we know the meaning of them.

If we have boolean expressions that are long, we may want to assign them to a variable so that we know what they’re checking.

Categories
JavaScript Best Practices

JavaScript Best Practices — Object Creation

Cleaning up our JavaScript code is easy with default parameters and property shorthands.

In this article, we’ll look at the best practices for object creation in our JavaScript code.

We’ll investigate the use of object literals, factory functions, Object.create and constructors/classes.

Object Literals

We can create objects with object literal notation. It requires no class, constructor, or prototype to create.

We just put everything inside curly braces as follows:

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

This is good for objects that are created only once.

If we need to create multiple objects that have the same structure, then we’ve to find another way.

Factory Functions

A factory function is a function that returns a new object.

For instance, we can write:

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

const obj = create();

We call the create object to return and assign the object:

{
  a: 1,
  b(){}
}

to obj .

Factory functions cause memory bloat since each object has its own unique copy of the b method.

Prototype Chains

We can create objects that inherit the properties of another object by using the Object.create method.

This kind of inheritance is called the prototype chain.

For instance, we can use the method as follows:

const create = () => {
  const parent = {
    a: 1,
    b() {}
  }
  return Object.create(parent);
};

const obj = create();

Now each object created with create inherit the properties of the parent object.

The object created always has the __proto__ property with the properties of parent .

ES5 Constructor Functions

Constructor functions are functions that act as templates for objects.

Each object created as fields and methods from the constructor function.

All instances of it reference those fields and methods.

For instance, we can define one as follows:

function Person(name) {
  this.name = name;
}

Person.prototype.greet = function() {
  return `hi ${this.name}`;
}

Then we can use the new keyword to make an instance of the Person constructor by writing:

function Person(name) {
  this.name = name;
}

Person.prototype.greet = function() {
  return `hi ${this.name}`;
}

const joe = new Person('joe');
const greeting = joe.greet();

The greet method is an instance method of the Person constructor, so we can call it on the object we created from the new keyword.

If we attach a method to the prototype property of the constructor, then it becomes method of the constructor.

We don’t want to use this anymore because it’s long, ugly, and error-prone.

ES6 Classes

The better way is to use ES6 classes, which is syntactic sugar on top of ES5 constructor functions.

They’re the same thing with a better syntax.

Therefore, we can rewrite the example above by writing:

class Person {
  constructor(name) {
    this.name = name;
  }

  greet() {
    return `hi ${this.name}`;
  }
}

const joe = new Person('joe');
const greeting = joe.greet();
console.log(greeting);

In the code above, the following:

class Person {
  constructor(name) {
    this.name = name;
  }

  greet() {
    return `hi ${this.name}`;
  }
}

is the same as:

function Person(name) {
  this.name = name;
}

Person.prototype.greet = function() {
  return `hi ${this.name}`;
}

The rest of the code is the same between both examples.

Performance

The class syntax is roughly 3 times faster than a factory function returning an object literal.

That’s more reason to use the ES6 class syntax. It’s faster for both developers and browsers.

Private Data

We can encapsulate private data with closures and weak maps.

We just have to add private variables to lets of classes and functions with let and const . Then they won’t be available outside the function.

Weak maps can only be retrieved if the reference to the key still exists. Once it’s destroyed, then the value of the given key is gone.

They all let us mix different properties into one constructor or object into one entity.

Conclusion

Object literals and factory functions provide easy ways to create one-off objects.

If we want to create multiple objects with the same structure, then we’ve to use classes or the Object.create method.

The class syntax creates objects faster than factory function, so that might be a plus for using classes.