Categories
JavaScript Best Practices

Maintainable JavaScript — Accidental Globals

Creating maintainable JavaScript code is important if want to keep using the code.

In this article, we’ll look at the basics of creating maintainable JavaScript code by looking at avoiding accidental creation of global variables.

Avoiding Accidental Globals

We should avoid accidental global variables.

If we’re writing JavaScript scripts, then we’ll create global variables by default if we assign a value to variables without using any keyword.

For instance, if we have:

count = 10;

then count is a global variable.

If we have a linter like JSHint or ESLint, then we’ll see a warning if we have something like that.

Also, strict mode will prevent us from creating global variables accidentally.

So if we have:

'use strict';
count = 10;

then we’ll get an error.

If we run the code above, we get ‘Uncaught ReferenceError: count is not defined’.

Strict mode is available in almost all modern browsers so we should use it.

Modules have strict mode on by default, so we’ll always get the error if we try to create new global variables.

Existing global variables should be treated as read-only.

We shouldn’t add any new properties to them to avoid errors.

For instance, if we use global variables like window or document , then we shouldn’t set any properties to them.

If we work with older code, we should update them whenever we can and enable strict mode.

One Global Object

Many libraries provide us with their own global objects that we can use in our code.

jQuery has the $ and jQuery objects.

The latter is added for compatibility with other libraries that use $ .

Vue has the Vue global variable to let us create a new Vue instance.

We create one global object with a unique name so that it’s unlikely that it’ll clash with other libraries in the app.

For instance, we may create our own constructor by writing:

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

Person.prototype.speak = function(speech) {
  console.log(`${this.name}: ${speech}`)
};

const james = new Person("james");
const mary = new Person("mary");
const jane = new Person("jane");

We create a Person constructor with the speak prototype method.

It takes the name parameter and assigns that to this.name .

Also, it has the speak instance method.

Then we can use it with the new operator.

This creates many global-scoped variables.

Instead of putting them all in the global scope, we put them in an object so that they aren’t global anymore.

For instance, we can write:

const obj = {};

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

obj.Person.prototype.speak = function(speech) {
  console.log(`${this.name}: ${speech}`)
};

const james = new obj.Person("james");
const mary = new obj.Person("mary");
const jane = new obj.Person("jane");

We put our Person constructor in the obj object so that the Person constructor isn’t in the global scope.

This way, we won’t be able to accidentally change it or overwrite it.

Conclusion

We put our code in an object so that they can’t be in the global scope.

Also, accidental global variables should be avoided with strict mode.

Categories
JavaScript Best Practices

Maintainable JavaScript — with and for Loop

Creating maintainable JavaScript code is important if want to keep using the code.

In this article, we’ll look at the basics of creating maintainable JavaScript code by looking at various block statements.

The with Statement

The with statement should never be used.

It was used for manipulating objects within its own context by creating a with block.

For instance, we could write:

var book = {
  title: "javascript for beginners",
  author: "james smith"
};

with(book) {
  message = `${title} by ${author}`;
}

to add the message property to book .

However, this isn’t allowed in strict mode because of its confusing scope.

We don’t know for sure from the code whether message is a global variable or a property of book .

The same issue prevents optimizations from being done since JavaScript engines may guess wrong.

Therefore, we should never use this.

It’s also forbidden in all style guides.

Linters can check for this so we won’t write with statements accidentally.

The for Loop

The for loop is one kind of loop in JavaScript that’s inherited from C and Java.

There’s also for for-in and for-of loop that lets us iterate through a property of an object and entries of iterable objects respectively.

For instance, we can write:

const values = [1, 2, 3, 4, 5],
  len = values.length;

for (let i = 0; i < len; i++) {
  console.log(values[i]);
}

We created a for loop to loop through some numbers by defining the values array and setting its length to len to cache it.

There’re 2 ways to change how the loop proceeds.

One if to use the break statement.

break will end the loop and not continue to the next iteration.

For instance, we can write:

const values = [1, 2, 3, 4, 5],
  len = values.length;

for (let i = 0; i < len; i++) {
  if (i === 2) {
    break;
  }
  console.log(values[i]);
}

to end the loop when i is 2.

Another way to change the loop behavior is with the continue keyword.

This lets us skip to the next iteration of the loop.

for instance, we can write:

const values = [1, 2, 3, 4, 5],
  len = values.length;

for (let i = 0; i < len; i++) {
  if (i === 2) {
    continue;
  }
  console.log(values[i]);
}

Then when i is 2, we’ll skip to the next iteration.

Some style guides like Doug Crockford’s style guide forbids the use of continue .

His reason is that it can be written better with conditions.

For instance, instead of writing:

const values = [1, 2, 3, 4, 5],
  len = values.length;

for (let i = 0; i < len; i++) {
  if (i === 2) {
    continue;
  }
  console.log(values[i]);
}

We can write:

const values = [1, 2, 3, 4, 5],
  len = values.length;

for (let i = 0; i < len; i++) {
  if (i !== 2) {
    console.log(values[i]);
  }
}

He says that it’s easier for programmers to understand conditionals than continue .

continue isn’t used very often as a loop control statement, so we can probably live without it and use conditionals.

Conclusion

with statement should never be used. It’s also disabled in strict mode.

Before using the continue keyword in loops, we should think twice.

Categories
JavaScript Best Practices

Maintainable JavaScript — Undefined, Arrays, and Objects

Creating maintainable JavaScript code is important if want to keep using the code.

In this article, we’ll look at the basics of creating maintainable JavaScript code with some conventions for undefined .

Undefined

undefined is a value that’s often confused with null .

This is partly because null == undefined returns true .

However, they’re actually very different from each other.

Variables that haven’t been assigned a value have the initial value of undefined .

This means it’s waiting for a real value to be assigned to it.

If we have:

let animal;
console.log(animal === undefined);

Then the console log will log true .

undefined shouldn’t be used much in our code.

But we need to check for them so that we’ll avoid all sorts of runtime errors.

We often get things that are undefined .

Non-existent properties have value undefined .

Parameters that haven’t have an argument passed in for it is also undefined .

If we try to do something to something that’s undefined , then we’ll get an error.

Therefore, we need to check for them.

To check for undefined , we can use the typeof operator.

If something is undefined , typeof will return 'undefined' .

For example, we can write:

let animal;
console.log(typeof animal);

Then we get 'undefined’ logged.

We shouldn’t use it for assignments, but we should check for them.

Object Literals

Object literals is a popular way to create objects with a set of properties.

It’s shorter than using the Object constructor and does the same thing.

Therefore, we should use the object literal notation to create an object.

For example, instead of writing:

let book = new Object();
book.title = "javascript for beginners";
book.author = "jane smith";

We should write:

let book = {
  title: "javascript for beginners",
  author: "jane smith"
}

It’s shorter and cleaner.

We just specify all the properties and values in between the curly braces.

We include the opening curly brace in the first line.

The properties are indented one level.

And the closing brace is in its own line.

Most style guides and linters suggest this format.

Guides like the Google style guide, Airbnb, style guide, ESLint default rules, etc. all look for this style.

Array Literals

Like object literals, we don’t need the Array constructor to create arrays.

Instead, we use the array literal notation.

For instance, instead of writing:

let fruits = new Array("apple", "orange", "grape");
let numbers = new Array(1, 2, 3, 4);

We write:

let fruits = ["apple", "orange", "grape"];
let numbers = [1, 2, 3, 4];

It’s much shorter and does the same thing.

It’s widely used and it’s common in JavaScript.

The Array constructor also has 2 versions.

It returns an array with the arguments if we pass in multiple arguments.

If there’s only one argument and it’s a nonnegative integer, then it creates an array with the number of empty slots as indicated by the argument.

Therefore, it’s another reason to avoid the Array constructor.

Conclusion

We can work with undefined , objects and arrays in better ways.

Literals are better than constructors for arrays and objects.

Categories
JavaScript Best Practices

Maintainable JavaScript — Switch

Creating maintainable JavaScript code is important if want to keep using the code.

In this article, we’ll look at the basics of creating maintainable JavaScript code by writing switch statements.

The switch Statement

switch statements are useful for doing something after checking for some value.

There are better ways to format swicth statements.

JavaScript switch statements behave differently than other languages.

Any type of value may be used with it.

And any expressions can be used with a valid case .

Other languages require the use of primitive values and constants respectively.

Switch Indentation

Switch statement’s content should be indented.

For instance, we write:

switch (condition) {
  case 1:
    // ...
    break;

  case 2:
    // ...
    break;

  case 3:
    // ...
    break;

  default:
    // ...
}

We indented the case statement and the content inside it.

The indentation is done with 2 spaces.

This makes the content easier to read.

We also have ab extra line before and after each case statement from the second one on.

Doug Crockford’s style guide has another suggestion.

The line between the case statements is removed.

For instance, we can write:

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

We remove the blank lines in between the parts of the switch statement.

However, all style guides have the same recommendation for indentation.

Falling Through

Accidentally omitting the break keyword at the end is a common mistake we make when we write switch statements.

This will cause the case statements below them to also run.

Some people suggest that every case should end with break , return or throw without exception.

This way, the case will end where we expect them to end.

If we make it clear in the code that falling through isn’t a mistake, then we can let the case statements fall through.

For example, we can write:

switch (condition) {

  // falls through
  case 1:
  case 2:
    // ...
    break;

  case 3:
    //...
    // falls through
  default:
    // ...
}

so that everyone knows that the fall through is intentional.

The first case falls to the 2nd.

And the 3rd falls to the default case.

They’re all marked with comments to communicate the programmer’s intent.

Some style guides, like Douglas Crockford’s style guide, don’t all fall throughs on switch ever.

But this depends on our team’s preference.

default

Some people also argue whether the default case is required.

Some believe that they should always be included.

It’s more like people follow this pattern.

However, if there’s no default case that we can think of to add, we may omit it.

If we omit the default case, we may communicate that with comments so that everyone knows it’s intentional.

For instance, we can write:

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

This way, we all know it’s not a mistake.

Conclusion

There’re several things to think about when we write switch statements.

breaks and default cases can be added or not, but we’ve to communicate our intent clearly.

This way, there won’t be any misunderstanding.

Categories
JavaScript Best Practices

Maintainable JavaScript — Numbers and Null

Creating maintainable JavaScript code is important if want to keep using the code.

In this article, we’ll look at the basics of creating maintainable JavaScript code with some conventions for numbers and null.

Numbers

There’s only one kind of number in JavaScript.

Integers and floats are stored with the same data type.

There’re various kinds of number literals that we can write.

For instance, we can write:

const count = 10;

to write an integer.

To write decimals, we can write:

let price = 10.0;
var quantity = 10.00;

We can have decimals after the number.

However, we can also write:

const count = 10.;

But this is confusing so we should avoid it.

The hanging decimal is also useless.

We can also have a leading decimal point with our JavaScript numbers:

var price = .2;

But it’s clearer to just put the 0 before the decimal point:

var price = 0.2;

We should never write octal literals since they’re confusing and are deprecated:

var num = 010;

The 0 cause confusion between octal and decimal numbers.

We can also write JavaScript hex numbers:

let num = 0xFF;

to write numbers in scientific notation, we can use the letter e:

var num = 1e20;

1e20 is 100000000000000000000 or 10 ** 20 .

The hanging and leading decimals can easily be confused for mistakes.

They‘re forbidden in many style guides and can be caught with ESLint, JSLint, and JSHint.

Warnings will also be made if octal literals are encountered.

Null

null is often misunderstood and confused with undefined .

We should use undefined most of the time to reduce confusion.

But we can use null in a few cases.

We can use them to initialize a variable that may be assigned with an object later.

Also, we can use it compare against a variable that may be null .

And we can pass that into a function where an object is expected.

We can also return null in place of an object when there’s nothing to return.

But we shouldn’t use null to test whether an argument is supplied.

And we don’t test uninitialized variables for null .

So we can write:

let person = null;

Or we can write:

function createPerson() {
  if (condition) {
    return new Person("nick");
  } else {
    return null;
  }
}

But we shouldn’t use it compare against an uninitialized variable like:

if (person != null) {
  doWork();
}

We also shouldn’t check against null to see if a variable is passed in:`

function doWork(arg1, arg2, arg3, arg4) {
  if (arg4 != null) {
    doSomething();
  }
}

We used != which is bad since it does automatic data type coercion and we check against null when we should be checking against undefined .

This is because if we don’t pass in an argument, then the parameter will be undefined .

null is a placeholder for objects.

It’s not a value to represent nothing.

Conclusion

We should be careful with placing decimal places with numbers.

Also, we shouldn’t use octal literals.

null should only be used in some limited cases.