Categories
JavaScript Best Practices

Better JavaScript — Things that Shouldn’t be Automatic

Spread the love

Like any kind of apps, JavaScript apps also have to be written well.

Otherwise, we run into all kinds of issues later on.

In this article, we’ll look at ways to improve our JavaScript code.

Problems with Coercions

Data coercions don’t change the data to the format we expect.

For instance, if we have:

const date = new Date("2020/12/31");
date == "2020/12/31"

Then the comparison would be false .

This is because date converted to a string it:

"Thu Dec 31 2020 00:00:00 GMT-0800 (Pacific Standard Time)"

The toString method converts to the format it wants.

To convert a date to YYYY/MM/DD format, we can write:

function toYMD(date) {
  const y = date.getFullYear(),
    m = date.getMonth() + 1,
    d = date.getDate();
    return `${y}/${(m < 10 ? "0" + m : m)}/${(d < 10 ? "0" + d : d)}`;
}

We get the year, month, and date.

Then we put them all in a string.

If the month or date has one digit, then we put a 0 before it.

Now we can compare them both as strings in the same format:

toYMD(date) === "2020/12/31";

Semicolon Insertion

JavaScript lets us drop the semicolon.

However, it just inserts it for us automatically.

This is called automatic semicolon insertion.

The JavaScript engine infers the semicolon into our program automatically.

The semicolon insertion mechanism is in the ES standard.

This means the mechanism is portable between JavaScript engines.

Semicolon insertion has its pitfalls.

We can’t avoid learning its rules if we skip the semicolon.

Semicolons are existing before a } character, after one or new lines, or at the end of program input.

We can only leave our semucolons at the end of a line, block or program.

So we can write:

function Point(x, y) {
  this.x = x || 0
  this.y = y || 0
}

But if we have:

function area(r) { r = +r return Math.PI * r ** 2 }

then we get an error.

Also, when the next input token can’t be parsed a semicolon is inserted.

So:

a = b
(foo());

is the same as:

a = b(foo());

But:

a = b
foo();

are parsed as 2 statements since:

a = b foo();

isn’t a valid JavaScript code.

We always have to pay attention to the start of the next statement to detect whether we can omit a semicolon.

We can’t leave off a semicolon if the next line’s first token can be interpreted as the continuation of the statement.

If we have:

a = b
["foo", "bar", "baz"].forEach((key) => {
  //...
});

Then it’s interpreted as:

a = b["foo", "bar", "baz"].forEach((key) => {
  //...
});

The bracket expression doesn’t make sense since we have multiple items inside it.

If we have:

a = b
/foo/i.test(str) && bar();

Then both lines are parsed as a single statement.

The first / is treated as the division operator.

Another problem is when we concatenate files without semicolons.

If we have:

file1.js

(function() {
  // ...
})()

file2.js

(function() {
  // ...
})()

then we may run into problems.

Both files contents may be treated as one statement when concatenated:

(function() {
  // ...
})()(function() {
  // ...
})()

We can concatenate the files after each file:

(function() {
  // ...
})();
(function() {
  // ...
})();

so we get won’t have to worry about the semicolons when concatenating.

Conclusion

There’re many issues with omitting semicolons.

We should just put them in ourselves rather than letting the JavaScript engine do it for us in the wrong place.

Likewise, we should avoid automatic coercions.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *