For more articles, please pay attention to the wechat public number: front-end CSS and JS dry goods

When reading JS code, have you ever had the feeling:

  • You barely understand what the code means?
  • Code that uses a lot of outdated JavaScript tricks?
  • Casual naming and coding style?

These are signs of bad coding habits.

This article lists five common bad coding habits in JavaScript. More importantly, this article gives practical advice on how to break these habits.

1. Do not use implicit conversions

JavaScript is a weakly typed language. When used properly, this is an advantage because it provides flexibility. Most operators + – * / == (excluding ===) use implicit type conversions when dealing with different types of data. if (condition) {… }, while(condition) {… } statements implicitly convert a condition to a Boolean value. The following example relies on implicit type conversions. I bet you’re confused:

console.log("2" + "1"); // => "21" console.log("2" - "1"); // => 1 console.log('' == 0); // => true console.log(true == []); // -> false console.log(true == ! []); // -> falseCopy the code

Over-reliance on implicit type conversions is a bad habit. First, it makes your code less stable in some cases. Second, it makes more bugs that are hard to reproduce and hard to fix.

Here is a function that gets the properties of an object. If the property does not exist, the function returns a default value:

function getProp(object, propertyName, defaultValue) { if (! object[propertyName]) { return defaultValue; } return object[propertyName]; } const hero = { name: 'Batman', isVillian: false }; console.log(getProp(hero, 'name', 'Unknown')); // => 'Batman'Copy the code

GetProp () reads the value of the name property, which is “Batman”.

What happens if you access the isVillian property:

console.log(getProp(hero, 'isVillian', true)); // => true
Copy the code

This is a mistake. Even if hero’s isVillian property is false, the function getProp() returns the false true. This is because the presence or absence of the attribute depends on passing the if (! object[propertyName]) {… } implicitly converts to a Boolean value. Such errors are hard to spot. To fix this function, you need to specify the type of the data.

function getPropFixed(object, propertyName, defaultValue) {

if (object[propertyName] === undefined) {

    return defaultValue;

}

return object[propertyName];

}

const hero = {

    name: 'Batman',

    isVillian: false

};

console.log(getPropFixed(hero, 'isVillian', true)); // => false
Copy the code

Object [propertyName] === undefined Verifies whether the operation result of the property accessor is undefined. Side note: section 4 recommends avoiding the direct use of undefined. So you can use the IN operator to improve the scheme:

function getPropFixedBetter(object, propertyName, defaultValue) { if (! (propertyName in object)) { return defaultValue; } return object[propertyName]; }Copy the code

Suggestion: Avoid using implicit type conversions whenever possible. Instead, make sure that variables and function parameters always have the same type. Use explicit type conversions when necessary.

List of best practices:

  • Always use the strict equality operator === to perform comparisons
  • Do not use the loose equality operator ==
  • The addition operator operand1+operand2: Both operands should be numbers or strings
  • Arithmetic operator – * / % : Both operands should be numbers
  • if (condition) {… }, while (condition) {… } and so on: condition should be a Boolean value
  • You might say that this approach requires more code… That’s true! But with explicit methods, you can control the behavior of your code. Plus, it adds readability.

2. Don’t use outdated JavaScript tricks

The interesting thing about JavaScript is that its founders didn’t anticipate how popular the language would become.

The complexity of applications built on JavaScript is growing faster than the language. This situation forces developers to use javaScript hacks to implement functionality.

A classic example is searching for whether an array contains an element. Use array. IndexOf (item)! == -1 to monitor the presence of elements. ECMAScript 2015 and beyond are becoming more powerful. You can safely refactor many hacks using the new language features.

Reconstruct array.indexof (item) using the ES2015 array.includes(item) method! = = 1.

3. Do not pollute the function scope

Before ES2015, js variables were function scoped, so you might have gotten into the bad habit of declaring all variables function scoped. Here’s an example:


function someFunc(array) {

    var index, item, length = array.length;

    /*

    * Lots of code

    */

    for (index = 0; index < length; index++) {

        item = array[index];

        // Use `item`

    }

    return someResult;

}

Copy the code

The variables index, item, and length are function scoped. But these variables pollute the function scope because they are only required in the for() block scope.

With the introduction of the block-scoped variable declaration keywords let and const, we should limit the lifetime of variables as much as possible.

Let’s fix the code above:

function someFunc(array) {

    /*

    * Lots of code

    */

    const length = array.length;

    for (let index = 0; index < length; index++) {

        const item = array[index];

        // Use `item`

    }

    return someResult;

}
Copy the code

Index and item variables exist only in the scope of the for() loop block. Length moves near its point of use. The refactored code is easier to understand because variables are not scattered throughout the function. They exist near the point of use.

Define variables in the block scope they use: the if block scope

// Let message; / /... if (notFound) { message = 'Item not found'; // Use `message` }Copy the code
// Good practice if (notFound) {const message = 'Item not found'; // Use `message` }Copy the code

For block scope

// Let item; for (item of array) { // Use `item` }Copy the code
For (const item of array) {// Use 'item'}Copy the code

4. Avoid undefined and NULL

Variables that have not been assigned a value are automatically evaluated as undefined. Such as:

let count;

console.log(count); // => undefined

const hero = {

    name: 'Batman'

};

console.log(hero.city); // => undefined
Copy the code

The count variable is defined but not initialized with a value. JavaScript implicitly assigns it undefined. Undefined is also returned when accessing the nonexistent property hero.city. Why is using undefined a bad habit? Because when we compare undefined directly, we may be dealing with variables whose state is uninitialized. Variables, object properties, and arrays must be initialized with values before being used! JavaScript provides many ways to avoid direct comparisons with undefine.

Does the attribute exist:

// Const object = {prop: 'value'}; if (object.nonExistingProp === undefined) { // ... } // Good practice const object = {prop: 'value'}; if ('nonExistingProp' in object) { // ... }Copy the code

Object Default properties

Function foo(options) {if (object.optionalProp1 === undefined) {object.optionalProp1 = 'Default value 1'; } / /... } function foo(options) {const defaultProps = {optionalProp1: 'Default value 1'}; options = { ... defaultProps, ... options }; / /... }Copy the code

Function default arguments

Function foo(param1, param2) {if (param2 === undefined) {param2 = 'Some default value'; } / /... } function foo(param1, param2 = 'Some default value') {//... }Copy the code

You should try to avoid returning NULL from functions, and you should also avoid calling functions with NULL as an argument. Once null is in your call stack, you must check for null variables in every function that may access null. This is cumbersome and error-prone, as follows:

function bar(something) { if (something) { return foo({ value: 'Some value' }); } else { return foo(null); } } function foo(options) { let value = null; if (options ! == null) { value = options.value; / /... } return value; }Copy the code

Write code that does not involve null values. One alternative is a try/catch mechanism. Tony Hoare, the inventor of ALGOL, once said:

I call it my billion dollar mistake… I’m designing the first comprehensive type system for references in an object-oriented language. But I can’t resist null references, simply because they are so easy to implement. This has led to countless errors, bugs, and system crashes that may have caused $1 billion in pain and loss over the past four decades.

“Computer Science’s Worst Mistakes” delves into why NULL impairs code quality.

5. Don’t use arbitrary coding styles

What could be more intimidating than reading code with a random coding style? You never know what will happen! What if the code base contains many developers with different coding styles? All kinds of characters graffiti walls.

The entire team and application code base are required to adopt the same coding style. It improves the readability of the code.

Examples of coding styles to consider:

  • Airbnb JavaScript Style Guide
  • Google JavaScript Style Guide

Recommended automated validation code style:

  • Install eslint
  • Configure ESLint with the coding style that works best for you
  • Set up a pre-commit hook to run ESLint validation before committing.

6. Summary

Writing high-quality and clean code requires discipline and overcoming bad coding habits. JavaScript is a weakly typed language with a lot of flexibility. But you have to know what features you’re using. The recommendation is to avoid implicit type conversions and reduce the use of undefined and NULL. The JS language has developed very rapidly in recent years. Find the tricky code and refactor it with the latest JavaScript features. A consistent coding style in the code base facilitates readability. What other bad coding habits do you know of in JavaScript?

Front-end CSS and JS by Dmitri Pavlutin