JS Tip of the Day: The Underscore Convention

The Underscore Convention
Level: Beginner

Sometimes you may see variables or properties in JavaScript code that are preceded by the underscore character (_).

class Candy {
    constructor () {
        this._ingredient = 'sugar';
    }
    isMadeOf (ingredient) {
        return this._ingredient === ingredient;
    }
}

While the underscore has no meaning to the JavaScript runtime, it does serve a purpose to the reader. In the above example, it’s used to show that the _ingredient property is to be considered private and should not be accessed outside of the class implementation.

let bar = new Candy();
console.log(bar.isMadeOf('sugar')); // true (allowed)
console.log(bar._ingredient === 'sugar'); // true (not as intended!)

Since the runtime doesn’t care if you use an underscore or not, it can’t tell you if you’re using such properties incorrectly. As a convention, it’s up to you to make sure you’re doing the right thing and not use these “private” properties unless done so within the class itself.

Underscore prefixes can also be used for parameter names indicating that, though an argument might be getting passed in that matches up with the parameter, the parameter may not be getting used in the function.

document.addEventListener('click', _event => {
    console.log('We got a MouseEvent, but are ignoring it');
});

This is helpful to the reader letting them see that, if this function needs to be modified in the future, even though a parameter may not be getting used now, it is available if needed.

In the case of unused parameters, linters may also complain. But linters like ESLint can be set up to recognize parameters with an underscore as an exception that can be ignored so no error will be reported if it goes unused.

You may also see parameters which are just underscores rather than being identifiers with an underscore prefix. These can, too, indicate unused parameters, but are often also used to indicate the propagation of a value through partial application.

let fiveUnlessSmaller = _ => Math.min(_, 5);
console.log(fiveUnlessSmaller(1)); // 1
console.log(fiveUnlessSmaller(10)); // 5

In the above example, the _ isn’t getting ignored, rather it’s getting passed on to Math.min() as one of its arguments. fiveUnlessSmaller() is a partially applied version of Math.min().

There’s one other underscore case worth mentioning, though it’s not related to the convention. If you ever see an underscore being used as an object or function, that probably means its from the underscore library.

let nums = [1, 2, 3];
let three = _.last(nums);
console.log(three); // 3

let mixed = _(nums).shuffle();
console.log(mixed); // [2, 3, 1]

Underscore is a library of utility functions and helpers popular in the JavaScript community. It’s usually represented as the global _ which can be used as a function or an object with a lot of other methods for performing common or useful tasks in JavaScript.

More info: