Airbnb JavaScript Style Guide

repository·master·Indexed 13 days ago

https://github.com/airbnb/javascript

A set of opinionated coding standards for JavaScript development designed to promote readability and maintainability. Includes guidelines for React, JSX, and CSS-in-JavaScript, as well as installation instructions for eslint-config-airbnb and eslint-config-airbnb-base (version 2.0.0).

Tokens
40.2K
Snippets
124
Records
136
Agent score
93%

What's inside Airbnb JavaScript Style Guide

  1. Use implicit returns for single-statement arrow functions

    master

    If an arrow function body consists of a single statement returning an expression without side effects, omit the braces and use an implicit return. Otherwise, use braces and an explicit return statement.

    Note: Do not use implicit returns for functions that have side effects (e.g., modifying a variable outside the function scope).

    // good: implicit return
    [1, 2, 3].map((number) => `A string containing the ${number + 1}.`);
    
    // good: explicit return for multi-line/complex logic
    [1, 2, 3].map((number) => {
      const nextNumber = number + 1;
      return `A string containing the ${nextNumber}.`;
    });
    
    // good: returning an object literal
    [1, 2, 3].map((number, index) => ({ [index]: number }));
    
    // No implicit return with side effects
    let bool = false;
    foo(() => {
      bool = true;
    });
  2. Include parentheses around arrow function arguments

    master

    Always include parentheses around arguments in arrow functions, even if there is only one argument. This ensures consistency and minimizes diff churn when adding or removing arguments later.

    // bad
    [1, 2, 3].map(x => x * x);
    
    // good
    [1, 2, 3].map((x) => x * x);
  3. Understand Primitives vs Complex Types

    master

    The style guide distinguishes between how data is accessed based on its type:

    • Primitives: When you access a primitive type, you work directly on its value. Primitives include string, number, boolean, null, undefined, symbol, and bigint. Note that symbol and bigint cannot be faithfully polyfilled and should only be used in environments that support them natively.
    • Complex Types: When you access a complex type, you work on a reference to its value. Complex types include object, array, and function.
    // Primitives: working with values
    const foo = 1;
    let bar = foo;
    bar = 9;
    console.log(foo, bar); // => 1, 9
    
    // Complex: working with references
    const foo = [1, 2];
    const bar = foo;
    bar[0] = 9;
    console.log(foo[0], bar[0]); // => 9, 9
  4. Choosing between Class, React.createClass, and Stateless functions

    master

    Select the component type based on your requirements for state and refs:

    • Use class extends React.Component: If your component requires internal state or refs. Avoid React.createClass.
    • Use normal functions: If your component does not have state or refs. Prefer standard function declarations over arrow functions or classes for stateless components.

    Note: Arrow functions for component definitions are discouraged because they rely on function name inference.

    // bad: using React.createClass
    const Listing = React.createClass({
      render() {
        return <div>{this.state.hello}</div>;
      }
    });
    
    // good: using ES6 class for state/refs
    class Listing extends React.Component {
      render() {
        return <div>{this.state.hello}</div>;
      }
    }
    
    // bad: using class without state/refs
    class Listing extends React.Component {
      render() {
        return <div>{this.props.hello}</div>;
      }
    }
    
    // bad: arrow function (discouraged name inference)
    const Listing = ({ hello }) => (
      <div>{hello}</div>
    );
    
    // good: normal function for stateless components
    function Listing({ hello }) {
      return <div>{hello}</div>;
    }
  5. Avoid confusing arrow syntax with comparison operators

    master

    Avoid writing arrow functions (=>) in a way that makes them easily confused with comparison operators (<=, >=). Use parentheses to wrap the expression or use a block with a return statement to improve clarity.

    // bad
    const itemHeight = (item) => item.height <= 256 ? item.largeSize : item.smallSize;
    
    // good: use parentheses
    const itemHeight = (item) => (item.height <= 256 ? item.largeSize : item.smallSize);
    
    // good: use a block
    const itemHeight = (item) => {
      const { height, largeSize, smallSize } = item;
      return height <= 256 ? largeSize : smallSize;
    };
  6. Format multi-line arrow function expressions

    master

    When an arrow function expression spans multiple lines, wrap the expression in parentheses to improve readability and clearly indicate where the function starts and ends.

    // good
    ['get', 'post', 'put'].map((httpMethod) => (
      Object.prototype.hasOwnProperty.call(
        httpMagicObjectWithAVeryLongName,
        httpMethod,
      )
    ));
  7. Avoid leading commas

    master

    Do not use leading commas in arrays or objects. Commas should follow the element they are separating.

    Enforced by ESLint rule: comma-style.

    // bad
    const story = [
        once
      , upon
      , aTime
    ];
    
    // good
    const story = [
      once,
      upon,
      aTime,
    ];
  8. Avoid iterators in favor of higher-order functions

    master

    To enforce immutability and easier reasoning, avoid using manual loops like for-in or for-of. Instead, use JavaScript's built-in higher-order functions.

    • For Arrays: map(), every(), filter(), find(), findIndex(), reduce(), some(), and forEach().
    • For Objects: Use Object.keys(), Object.values(), or Object.entries() to convert object data into arrays that can then be processed with higher-order functions.

    Note: Do not use generators, as they do not transpile well to ES5.

    const numbers = [1, 2, 3, 4, 5];
    
    // bad
    let sum = 0;
    for (let num of numbers) {
      sum += num;
    }
    
    // good
    let sum = 0;
    numbers.forEach((num) => {
      sum += num;
    });
    
    // best (use the functional force)
    const sum = numbers.reduce((total, num) => total + num, 0);
  9. Ensure class methods use `this` or are static

    master

    Class methods should either use this (indicating they behave differently based on the instance) or be declared as static methods if they do not require instance properties. Avoid instance methods that do not access any instance state.

    // bad
    class Foo {
      bar() {
        console.log('bar');
      }
    }
    
    // good: uses this
    class Foo {
      bar() {
        console.log(this.bar);
      }
    }
    
    // good: static method
    class Foo {
      static bar() {
        console.log('bar');
      }
    }
  10. When to use inline styles

    master

    Use inline styles only for high cardinality values (e.g., values derived directly from a component prop). Do not use inline styles for low cardinality styles (discrete sets of styles), as generating themed stylesheets for every variation can be expensive. For low cardinality styles, use the css() utility with a pre-defined style object.

    // Good: Using css() for low cardinality (discrete) styles
    function MyComponent({ styles, spacing }) {
      return <div {...css(styles.periodic, { margin: spacing })} />;
    }
    
    // Bad: Using inline style for low cardinality
    function MyComponent({ spacing }) {
      return <div style={{ display: 'table', margin: spacing }} />;
    }
  11. Warning: Bitwise operations return 32-bit integers

    master

    Be cautious when using bitshift operations for type coercion. While JavaScript numbers are 64-bit, bitshift operations always return a 32-bit signed integer. This can cause unexpected behavior for integer values larger than 2,147,483,647.

    If you must use bitshifting for performance reasons, include a comment explaining why.

    // Example of 32-bit overflow
    2147483647 >> 0; // => 2147483647
    2147483648 >> 0; // => -2147483648
    
    // If using for performance, document it:
    /**
     * parseInt was the reason my code was slow.
     * Bitshifting the String to coerce it to a
     * Number made it a lot faster.
     */
    const val = inputValue >> 0;