FB Web Tips

Cargo-Culting in JavaScript

By James Padolsey

Cargo-cult programming is what a programmer does when he or she doesn’t know a particular language or paradigm well enough, and so ends up writing redundant and possibly harmful code. It rears its head quite often in the land of JavaScript. In this article, I explore the concept of cargo-cult programming and places to watch out for it in JavaScript.

 

Dogmatic rules surface and spread, until they are considered the norm.

Cargo-culting is sometimes defined as “the extreme adherence to the form instead of content.” The form, in programming, being the syntax, paradigms, styles and patterns that we employ. The content being the abstract thing that you are seeking to represent through your code — the very substance of your program. A person with lacking understanding in an area is likely to copy the form of others without truly understanding, and thus their content — their program — can suffer.

Cargo-culting is curiously common in JavaScript, probably because of the general low barrier to entry in the front-end development world. You can whip up an HTML page with a bit of JavaScript in seconds. As a result, there are many people who become sufficiently proficient in these technologies to feel comfortable creating and imposing rules on themselves and others. Eventually, other newcomers copy these rules. Dogmatic rules surface and spread, until they are considered the norm:

  • Always use strict equality operators
  • Never use eval
  • Always use a single var declaration per scope
  • Always use an IIFE – it “protects” you

A rule continues to spread until a programmer is only using a given technique because of its popularity, instead of considering each specific use-case independently.


JavaScript Abuzz with Semi-colons

If you’ve had the opportunity to witness the witty banter and rhetoric of the software developer over the years, you will have spotted a tendency to discuss seemingly tiny things at great lengths. Things like the semi-colon, the comma, white-space or the curly brace.

Syntax like semi-colons or white-space may seem to purely be elements of form, not of content. But many of these subtle syntax rules can have significant effects in JavaScript. If you don’t understand the ‘form’ then you cannot begin to understand the ‘content’.

So in this article, we will identify what areas of form in JavaScript are frequently cargo-culted off of — that is, copied without understanding.

How JavaScript can seem

How JavaScript can seem… an image from Angus Croll’s “The Politics Of JavaScript” presentation


Undefined

Angus Croll, in a recent presentation, titled “The Politics Of JavaScript“, highlighted one of the most common pieces of JS dogma that people cargo-cult off of:

if (typeof myObject.foo === 'undefined') {...}

Most of the time, doing such a long-winded check for undefined is pointless. The technique became common because people were copying other people, not because of it’s actual value.

Of course, there are times when:

typeof x === 'undefined'

… is preferable to:

x === undefined

But, equally, there are times when the latter is preferred. A quick overview of the options:

// Determine if `x` is undefined:
x === undefined
typeof x == 'undefined'
typeof x === 'undefined'
x === void 0

// Determine if `x` is undefined OR null:
x == null
x == undefined

People started using the typeof approach because they were protecting themselves against:

  • A potentially undeclared variable (non-typeof approaches would throw TypeErrors)
  • Someone overwrote undefined globally or in a parent scope. Some environments allow you to overwrite undefined to something like true. You have to ask yourself: “Is it likely that someone overwrote undefined, and should my script have to pander to such silliness?

But most of the time they’re protecting themselves from having to worry. It’s a catch-all avoidance of having to know the details. Knowing the details can help you though. Every character of your code should exist with a purpose in mind.

The only time that you should need to use a typeof check for undefined is when you are checking for a variable that may not have been declared, e.g. checking for jQuery in the global scope:

if (typeof jQuery != 'undefined') {
    // ... Use jQuery
}

The thing is, if jQuery does exist, then we can be sure that it’s an object – a “truthy” thing. So this would be sufficient:

// or:
if (window.jQuery) {

}

The Great Strict/non-strict Debate

Let’s take something very common and generally considered good advice, solely using strict-equality:

a === b

Strict-equality is said to be good because it avoids ambiguity. It checks both the value and the type, meaning that we don’t have to worry about implicit coercion. With non-strict equality, we do have to worry about it though:

1 == 1    // true — okay, that's good
1 == "1"  // true — hmm
1 == [1]  // true — wat!?

So it would seem sensible advice to entirely avoid non-strict equality, right? Actually, no. There are many situations where strict-equality creates large amounts of redundancy, and non-strict equality is preferable.

When you know, with 100% certainty, that the types of both operands are the same, you can avoid the need for strict-equality. For example, I always know that the typeof operator returns a string, and my right-hand operand is also a string (e.g. "number"):

// With strict-equals
typeof x === 'number'

// With non-strict-equals:
typeof x == 'number'

They’re both effectively identical. I am not necessarily suggesting that we abandon strict-equals in this case — I am suggesting that we remain aware of what we’re doing so that we can make the best choices given each situation.

Another quite useful example is when you want to know if a value is either null or undefined. With strict equality, you might do this:

if (value === undefined || value === null) {
    // ...
}

With non-strict equality, it’s far simpler:

if (value == null) {
    // ...
}

There is no catch here — it is doing exactly what we want, only, arguably, less visibly. But, if we know the language, then what’s the problem? It’s right there in the spec:

The comparison x == y, where x and y are values, produces true or false. Such a comparison is performed as follows:

  • If x is null and y is undefined, return true.
  • If x is undefined and y is null, return true.

If you’re writing JavaScript with the intention of it being read, if at all, by people that know JavaScript, then I would argue that you shouldn’t feel bad taking advantage of implicit language rules

I've worked very hard for this, so please help me by donating a cup of coffee. Thanks in advance.

0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

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