# se-javascript-style-guide

> Javascript style guide - follow or get call from police

Latest version **1.0.3** (published 2019-11-15) · ISC license · 0 weekly downloads

## Install

```sh
npm install se-javascript-style-guide
pnpm add se-javascript-style-guide
yarn add se-javascript-style-guide
bun add se-javascript-style-guide
```

## Health

**Score 15/100 (F)** — status: abandoned.

Positive: no vulnerabilities.

Warnings: low downloads; no types; no esm support.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 1.0.3 |
| Published | 2019-11-15 |
| First published | 2018-11-02 |
| Weekly downloads | 0 |
| License | ISC |
| TypeScript types | none |
| Module format | CommonJS |
| Dependencies | 0 |
| Unpacked size | 73.9 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Author | The good folks at Simple Energy |
| Maintainers | simpleenergy_admin |

## Links

- npm: https://www.npmjs.com/package/se-javascript-style-guide
- npm.io page: https://npm.io/package/se-javascript-style-guide

## Recent versions

- 1.0.3 (latest) — 2019-11-15
- 1.0.3-rc.0 — 2018-11-02

## README

# Simple Energy Javascript Style Guide

**How to use:** Read through all of the sections below to understand, generally, our preferred implementation. The _**Implementation Standards**_ section should be well understood committed to memory, so-to-speak. The _**Syntax Rules**_ section should be read over thoroughly, but doesn't need to be memorized since the rules are enforced by our [eslint configuration package](https://github.com/simpleenergy/style-guide-javascript/tree/master/packages/eslint-config).

Please keep in mind that there are many enforced syntax rules that are not outlined in this guide (we've only highlighted the most frequently violated rules here). If you are not clear about the meaning a lint error, or you are not sure how to repair the error, please refer to the [eslint documentation](https://eslint.org/) to remediate.


<a name="table-of-contents"></a>
**I. Implementation Standards**
  1. [Thorough Consideration](#thorough-consideration)
  1. [Naming Things](#naming-things)
  1. [Consistent References](#consistent-references)
  1. [Immutability](#immutability)
  1. [Object Oriented & Functional Approaches](#oop-and-fp-oop)
  1. [Testing](#testing)

**II. Syntax Rules**
  1. [References](#references)
  1. [Objects](#objects)
  1. [Arrays](#arrays)
  1. [Destructuring](#destructuring)
  1. [Strings](#strings)
  1. [Functions](#functions)
  1. [Arrow Functions](#arrow-functions)
  1. [Classes & Constructors](#classes--constructors)
  1. [Modules](#modules)
  1. [Iterators and Generators](#iterators-and-generators)
  1. [Variables](#variables)
  1. [Comparison Operators & Equality](#comparison-operators--equality)
  1. [Blocks](#blocks)
  1. [Control Statements](#control-statements)
  1. [Comments](#comments)
  1. [Commas](#commas)
  1. [Semicolons](#semicolons)
  1. [Type Casting & Coercion](#type-casting--coercion)
  1. [Accessors](#accessors)
  1. [Events](#events)


## I. IMPLEMENTATION STANDARDS

  ### Thorough Consideration

  <a name="thorough-consideration"></a>
  - [1.1](#thorough-consideration) In general, implementation should be an expression of thorough analysis of the problem to be solved, and careful evaluation of side-effects of various strategies. Rushing into an implementation strategy often leads to an increased level of effort and limited extendability. Don't start writing until you have planned your implementation from beginning to end - including a plan for managing deployment and maintaining backward compatibility.

    Here are some questions you should be asking when considering solutions:
    - What is the simplest solution?
    - Is this solution open for extension?
    - Have I considered a variety of possible solutions?
    - Am I using the right tool for the right job?
    - What effect will this implementation have on other areas of the system?
    - Will others be able to easily understand what I am doing?

**[⬆ back to top](#table-of-contents)**

### Naming Things
  <a name="naming-things"></a>
  - [2.1](#naming-things) Do not be terse when naming things. The names you assign should clearly summarize the object being named. Consider the statement `const a = b + c;`. While it is a valid statement, it does not provide any context as to it's purpose. The same statement, rewritten as `const totalHarvest = barleyHarvest + alfalfaHarvest;` is much easier reason about because it's context is clear. Avoid short, ambiguous names; be descriptive.

    ```javascript
    // bad
    const sh = 'corn';

    // good
    const springHarvest = 'corn';
    ```

  <a name="naming-camelCase"></a>
  - [2.2](#naming-camelCase) Use camelCase when naming objects, functions, and instances.

    ```javascript
    // bad
    const DillPickles = {};
    const delicious_dill_pickle = {};
    function EatPickle() {}

    // good
    const deliciousDillPickle = {};
    function eatPickle() {}
    ```

  <a name="naming-PascalCase"></a>
  - [2.3](#naming-PascalCase) Use PascalCase only when naming constructors or classes.

    ```javascript
    // bad
    function farmHand(options) {
      this.name = options.name;
    }

    const farmHand = new farmHand({
      name: 'Old McDonald',
    });

    // good
    class FarmHand {
      constructor(options) {
        this.name = options.name;
      }
    }

    const farmHand = new FarmHand({
      name: 'Old McDonald',
    });
    ```

  <a name="naming-filename-matches-export"></a>
  - [2.4](#naming-filename-matches-export) A base filename should exactly match the name of its default export. Omit `index.js` if importing an index from a directory.

    ```javascript
    // file 1 contents in ./Crop/index.js
    class Crop {
      // ...
    }
    export default Crop;

    // file 2 contents
    export default function maxYield() { return 999; }

    // file 3 contents
    export default function totalAllCrops() {}

    // in some other file
    // bad
    import Crop from './Crop/index';
    import maxYield from './MaxYield';
    import totalAllCrops from './totalAllCrops';

    // good
    import Crop from './Crop';
    import maxYield from './maxYield';
    import totalAllCrops from './totalAllCrops';
    ```

  <a name="naming-camelCase-default-export"></a>
  - [2.5](#naming-camelCase-default-export) Use camelCase when you export-default a function. Your filename should be identical to your function’s name.

    ```javascript
    function feedTheCattle() {
      // ...
    }

    export default feedTheCattle;
    ```

  <a name="naming-PascalCase-singleton"></a>
  - [2.6](#naming-PascalCase-singleton) Use PascalCase when you export a constructor / class / singleton / function library / bare object.

    ```javascript
    const TasksOnTheFarm = {
      irrigate: {
      },
    };

    export default TasksOnTheFarm;
    ```

  <a name="naming-Acronyms-and-Initialisms"></a>
  - [2.7](#naming-Acronyms-and-Initialisms) Acronyms and initialisms should always be all capitalized, or all lowercased.

    ```javascript
    // bad
    import GmoFree from './GmoFree';

    // good
    import GMOFree from './GMOFree';

    // good
    import gmoFree from './gmoFree';

    ```

  <a name="naming-uppercase"></a>
  - [2.8](#naming-uppercase) Use uppercase names (with underscores) for application wide constants, especially configuration variables.

    ```javascript
    // bad
    const LOCAL_VARIABLE = 'should not be uppercased';

    // good
    export const API_KEY = 'SOMEKEY';

    // good
    export const SOME_FARM = {
      FARM_REGION: 'Colorado',
    };
    ```

  <a name="naming-module-imports"></a>
  - [2.9](#naming-module-imports) Name imported npm modules consistently with module name. Constructors are uppercase, functions start with lowercase

  ```javascript
  // bad
  import classNames from 'classnames';
  import ClassNames from 'class-names';
  import classnames from 'class-names';

  // good
  import classnames from 'classnames'; // Function default export
  import classNames from 'class-names'; // Function default export

  // good
  import Classnames from 'classnames'; // Constructor default export
  import ClassNames from 'class-names'; // Constructor default export
  ```


**[⬆ back to top](#table-of-contents)**

### Consistent References

  <a name="consistent-references"></a>
  - [3.1](#consistent-references) Do not rename a parameter reference if it's value is not modified by the function. _Renaming or mapping unmodified references makes it very difficult to track values through a call chain._

  ```javascript
    // bad
    function plantCrop(crop, farmer) {
      return {
        field: crop,
        worker: farmer,
        plantedOn: new Date(),
      }
    }

    function waterCrop({ field, worker, datePlanted }) {
      return {
        cropType: field,
        farmHand: worker,
        planted: datePlanted,
        wateredOn: new Date(),
      }
    }

    function harvestCrop({ cropType, farmHand, planted, wateredOn }) {
      const threeMonthsInMilliseconds = 7776000000;
      const threeMonthsAgo = new Date().getTime() - threeMonthsInMilliseconds;

      if (plantedOn < threeMonthsAgo) {
        return {
          harvested: harvestedCrop,
          farmer: farmHand,
          plantedDate: planted,
          wateredDate: wateredOn,
          harvestedOn: new Date()
        }
      }
    }

    const plantedCrop = plantCrop('Amy', 'Walnut');
    const wateredCrop = waterCrop(plantedCrop);
    const harvestedCrop = harvestCrop(wateredCrop);

    // plantedCrop.field = 'Walnut'
    // wateredCrop.cropType = 'Walnut'
    // harvestedCrop.harvested = 'Walnut'

    // good
    function plantCrop(crop, farmer) {
      return {
        crop,
        farmer,
        plantedOn: new Date(),
      }
    }

    function waterCrop({ crop, farmer, plantedOn }) {
      return {
        crop,
        farmer,
        plantedOn,
        wateredOn: new Date(),
      }
    }

    function harvestCrop({ crop, farmer, plantedOn, wateredOn }) {
      const threeMonthsInMilliseconds = 7776000000;
      const threeMonthsAgo = new Date().getTime() - threeMonthsInMilliseconds;

      if (plantedOn >  threeMonthsAgo) {
        return {
          crop,
          farmer,
          plantedOn,
          wateredOn,
          harvestedOn: new Date(),
        }
      }
    }

    const plantedCrop = plantCrop('Amy', 'Walnut');
    const wateredCrop = waterCrop(plantedCrop);
    const harvestedCrop = harvestCrop(wateredCrop);

    // plantedCrop.crop = 'Walnut'
    // wateredCrop.crop = 'Walnut'
    // harvestedCrop.crop = 'Walnut'
  ```

  <a name="consistent-references-modified"></a>
  - [3.2](#consistent-references-modified) When deriving a value from a given reference, assign a name to the derivative that contains some reference to the original name. _This provides useful context for understanding the source of the new reference._

  ```javascript
    // bad
    function washFruit(fruitName) {
      const replaced = fruitName.replace(/(moldy|dirty)/, '');
      return `Enjoy your delicious ${replaced}`;
    }

    // good
    function washFruit(fruitName) {
      const fruitNameCleaned = fruitName.replace(/(moldy|dirty)/, '');
      return `Enjoy your delicious ${fruitNameCleaned}`;
    }

    // bad
    const result = veggies.filter(veggie => veggie.ripe);

    // good
    const veggiesFiltered = veggies.filter(veggie => veggie.ripe);
  ```

**[⬆ back to top](#table-of-contents)**

### Immutability

  <a name="immutability"></a>
  To avoid unwanted mutations, don't work directly on a reference. Instead, create a copy of the object first or use a pure function that constructs a new reference with transformed values. The following patterns can be used to avoid unwanted mutations on `object`s and `array`s.

  <a name="immutability-shallow-copy-object"></a>
  - [4.1](#immutability-shallow-copy-object) **Shallow copy object:** Use the spread operator to copy object references. This also provides a convenience for updating values on the new copy.

    ```JavaScript
    const harvest = {
      type: 'Hops',
      weight: '22kg',
    }

    const harvestAfterDamage = {
      ...crop,
      weight: '19kg',
    }
    ```
  <a name="immutability-deep-copy-object"></a>
  - [4.2](#immutability-deep-copy-object) **Deep copy object:** Use a recursive function to clone all deeply nested object properties.
    ```JavaScript
    const harvest = {
      type: 'Hops',
      stats: {
        weight: '22kg',
        harvestedBy: 'John Farmhand'
      },
    }

    function cloneObject(obj) {
      const clone = {};

      for (let i in obj) {
        if (obj[i] !== null && typeof obj[i] === 'object') {
          clone[i] = cloneObject(obj[i]);
        } else {
          clone[i] = obj[i];
        }
      }

      return clone;
    }

    const clonedHarvest = cloneObject(crop);
    ```

  <a name="immutability-copy-array"></a>
  - [4.3](#immutability-copy-array) **Copy array:** Use the spread operator to copy array references. This also provides a convenience for adding values to the new copy.

    ```JavaScript
    const veggies = ['tomato', 'cucumber', 'potato'];
    const moreVeggies = [...veggies, 'celery'];
    ```

  <a name="immutability-shallow-copy-array"></a>
  - [4.4](#immutability-shallow-copy-array) **Shallow copy object array:** Use a functional array method to return a new array of copied objects.

    ```javascript
    const veggies = [
      {
        name: 'tomato',
        color: 'red'
      },
      {
        name: 'potato',
        color: 'brown'
      }
    ];

    const moreVeggies = veggies.map(veggie => {
      return {
        ...veggie
      };
    });
    ```

**[⬆ back to top](#table-of-contents)**


### Object Oriented & Functional Approaches

  <a name="oop-and-fp-oop"></a>
  - [5.1](#oop-and-fp-oop) **Object Oriented:** When a feature you are writing relies on identity, state and methods, it is best to use an object oriented approach. Particularly, if the piece of functionality will be appropriated across a number of implementations and be extended over time, it is best to encapsulate the functionality using ES6 classes so that it is decoupled from the constraints of the application framework.

  - [5.2](#oop-and-fp-fp) **Functional:** When a piece of functionality is required only for transforming data and has no need to maintain identity or state, a functional implementation is preferred, especially when collected into reusable modules.

  - [5.3](#oop-and-fp-always) **Always:** Even when using an OOP approach, you should endeavor to apply functional paradigms to the overall design; minimizing state changes and side-effects should always be a primary concern. When mutations are required, try to relegate them to one location so that they are easier to monitor and maintain.

**[⬆ back to top](#table-of-contents)**


### Testing
  <a name="testing"></a>
  - Whichever testing framework you use, you should be writing tests!
  - 100% test coverage is a good goal to strive for, even if it’s not always practical to reach it.
  - Strive to cover all branching logic; many bugs result from poorly implemented control flow.
  - Whenever you fix a bug, _write a regression test_. A bug fixed without a regression test is almost certainly going to break again in the future.

**[⬆ back to top](#table-of-contents)**

## II. SYNTAX RULES

### References

<a name="references"></a>

- [1.1](#references) Use `const` for all of your references; this will help ensure immutability of reference values. If you must reassign a reference, use `let`. Do not use `var` as it is function-scoped, rather than block-scoped.

  When you access a primitive type `string`, `number`, `boolean`, `null`, `undefined`, and `symbol`, you work directly on its *value*. When you access a complex type like `object`, `array`, and `function`, you work on a *reference* to it's value.

  **No symbols**: Symbols cannot be faithfully polyfilled, so they should not be used when targeting browsers/environments that don’t support them natively.

**[⬆ back to top](#table-of-contents)**

### Objects

  <a name="es6-object-concise"></a>
  - [2.1](#es6-object-concise) Use property value shorthand, object method shorthand, and group your shorthand properties at the beginning of your object declaration.

    ```javascript
    const farmParam = 'some_param';
    const farmName = 'Some Farm';

    // bad
    const farm = {
      farmHands: [],
      hasFruit: true,
      hasVeggies: false,
      farmName: farmName,
      hasLivestock: true,
      farmParam: farmParam,

      addFarmHand: function (name) {
        return this.farmHands.push(name);
      }
    };

    // good
    const farm = {
      farmName,
      farmParam,
      farmHands: [],
      hasFruit: true,
      hasVeggies: false,
      hasLivestock: true,

      addFarmHand(name) {
        return this.farmHands.push(name);
      },
    };
    ```

**[⬆ back to top](#table-of-contents)**


  ### Arrays

  <a name="arrays--push"></a>
  - [3.1](#arrays--push) Use `push` instead of direct assignment to add items to an array.

    ```javascript
    const farmersWardrobe = [];

    // bad
    farmersWardrobe[farmersWardrobe.length] = 'Overalls';

    // good
    farmersWardrobe.push('Overalls');
    ```

  <a name="arrays--from-iterable"></a>
  - [3.2](#arrays--from-iterable) To convert an iterable object to an array, use spreads `...` instead of `Array.from`.

    ```javascript
    const fruitListing = document.querySelectorAll('.fruit__list');

    // good
    const fruitNodes = Array.from(fruitListing);

    // best
    const fruitNodes = [...fruitListing];
    ```

  <a name="arrays--from-array-like"></a>
  - [3.3](#arrays--from-array-like) Use `Array.from` for converting an array-like object to an array.

    ```javascript
    const typesOfVeggies = { 0: 'squash', 1: 'carrot', 2: 'celery' };

    // bad
    const veggies = Array.prototype.slice.call(typesOfVeggies);

    // good
    const veggies = Array.from(typesOfVeggies);
    ```

  <a name="arrays--callback-return"></a>
  - [3.4](#arrays--callback-return) Use return statements in array method callbacks. It’s ok to omit the return if the function body consists of a single statement returning an expression without side effects.

    ```javascript
    // good
    ['squash', 'carrot', 'celery'].map((veggie) => {
      return `I love ${veggie}`;
    });

    // good
    ['squash', 'carrot', 'celery'].map(veggie => `I love ${veggie}`);
    ```

**[⬆ back to top](#table-of-contents)**

### Destructuring

  <a name="destructuring--object"></a>
  - [4.1](#destructuring--object) Use object destructuring when accessing and using multiple properties of an object.

    ```javascript
    // bad
    function getFruitName(fruit) {
      const genus = fruit.genus;
      const species = fruit.species;

      return `${genus} ${species}`;
    }

    // good
    function getFruitName(fruit) {
      const { genus, species } = fruit;
      return `${genus} ${species}`;
    }

    // best
    function getFruitName({ genus, species }) {
      return `${genus} ${species}`;
    }
    ```

  <a name="destructuring--array"></a>
  - [4.2](#destructuring--array) Use array destructuring.

    ```javascript
    const veggies = ['squash', 'carrot', 'celery'];

    // bad
    const firstVeggie = veggies[0];
    const secondVeggie = veggies[1];

    // good
    const [firstVeggie, secondVeggie] = veggies;
    ```

  <a name="destructuring--object-over-array"></a>
  - [4.3](#destructuring--object-over-array) Use object destructuring for multiple return values, not array destructuring.

    ```javascript
    // bad
    function tillTheSoil(input)
      return [north, south, east, west];
    }

    // the caller needs to think about the order of return data
    const [north, __, east] = tillTheSoil(input);

    // good
    function tillTheSoil(input) {
      return { north, south, east, west };
    }

    // the caller selects only the data they need
    const { north, east } = tillTheSoil(input);
    ```

**[⬆ back to top](#table-of-contents)**

### Strings

  <a name="strings--quotes"></a>
  - [5.1](#strings--quotes) Use single quotes `''` for strings.

  <a name="strings--line-length"></a><a name="4.2"></a>
  - [5.2](#strings--line-length) Strings that cause the line to go over 100 characters should not be written across multiple lines using string concatenation.

    ```javascript
    // bad
    const errorMessage = 'Growing and harvesting crops requires many tasks. ' +
      'Before the crop is planted, preparing the soil with disking, tilling ' +
      '(vertical or horizontal), and fertilizing is sometimes required.';

    // good
    const errorMessage = 'Growing and harvesting crops requires many tasks. Before the crop is planted, preparing the soil with disking, tilling (vertical or horizontal), and fertilizing is sometimes required.';
    ```

  <a name="es6-template-literals"></a>
  - [5.3](#es6-template-literals) When programmatically building up strings, use template strings instead of concatenation.
    ```javascript
    // bad
    function enjoyFruit(fruitName) {
      return 'Golly, I sure love ' + fruitName + '?';
    }

    // good
    function enjoyFruit(fruitName) {
      return `Golly, I sure love ${fruitName}?`;
    }
    ```

**[⬆ back to top](#table-of-contents)**

### Functions

  <a name="functions--declarations"></a><a name="5.1"></a>
  - [6.1](#functions--declarations) Use named function expressions instead of function declarations.

    ```javascript
    // bad
    function pickFruit() {
      // ...
    }

    // bad
    const pickFruit = function () {
      // ...
    };

    // good
    // lexical name distinguished from the variable-referenced invocation(s)
    const pickFruit = function pickFruitInTheSummer() {
      // ...
    };
    ```

  <a name="es6-rest"></a>
  - [6.2](#es6-rest) Never use `arguments`, opt to use rest syntax `...` instead.
    ```javascript
    // bad
    function makeSmoothieFromFruits() {
      const fruits = Array.prototype.slice.call(arguments);
      return fruits.join('');
    }

    // good
    function makeSmoothieFromFruits(...fruits) {
      return fruits.join('');
    }
    ```

  <a name="es6-default-parameters"></a>
  - [6.3](#es6-default-parameters) Use default parameter syntax rather than mutating function arguments.

    ```javascript
    // bad
    function makeDinner(ingredients) {
      ingredients = ingredients || {};
      // ...
    }

    // good
    function makeDinner(ingredients = {}) {
      // ...
    }
    ```

  <a name="functions--defaults-last"></a>
  - [6.4](#functions--defaults-last) Always put default parameters last.

    ```javascript
    // bad
    function makeDinner(ingredients = {}, participants) {
      // ...
    }

    // good
    function makeDinner(participants, ingredients = {}) {
      // ...
    }
    ```

  <a name="functions--mutate-params"></a><a name="6.6"></a>
  - [6.6](#functions--mutate-params) Never mutate parameters.

    ```javascript
    // bad
    function fruit(type) {
      type.name = 'melon';
    }

    // good
    function fruit(type) {
      const fruitName = Object.prototype.hasOwnProperty.call(type, 'name') ? type.name : 'melon';
    }
    ```

  <a name="functions--reassign-params"></a><a name="6.7"></a>
  - [6.7](#functions--reassign-params) Never reassign parameters.

    ```javascript
    // bad
    function fruit(name) {
      name = 'tomato';
    }

    // good
    function fruit(name) {
      const fruitName = name || 'tomato';
      // ...
    }
    ```

**[⬆ back to top](#table-of-contents)**

### Arrow Functions

  <a name="arrows--use-them"></a>
  - [7.1](#arrows--use-them) When you must use an anonymous function (as when passing an inline callback), use arrow function notation.

    ```javascript
    // bad
    ['squash', 'carrot', 'celery'].map(function (veggie) {
      return `I love ${veggie}`;
    });

    // good
    ['squash', 'carrot', 'celery'].map((veggie) => {
      return `I love ${veggie}`;
    });
    ```

  <a name="arrows--implicit-return"></a>
  - [7.2](#arrows--implicit-return) If the function body consists of a single statement returning an [expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Expressions) without side effects, omit the braces and use the implicit return. Otherwise, keep the braces and use a `return` statement.

    ```javascript
    // bad
    ['squash', 'carrot', 'celery'].map(number => {
      return `I love ${veggie}`;
    });

    // good
    ['squash', 'carrot', 'celery'].map(veggie => `I love ${veggie}`);

    // good
    let totalVeggies = 0;

    ['squash', 'carrot', 'celery'].map((veggie) => {
      totalVeggies += 1;
      return `I've eaten ${totalVeggies} veggies`;
    });

    // good
    ['squash', 'carrot', 'celery'].map((veggie) => ({
      name: veggie,
    }));
    ```


**[⬆ back to top](#table-of-contents)**
### Classes & Constructors

  <a name="constructors--use-class"></a>
  - [8.1](#constructors--use-class) Always use `class`. Avoid manipulating `prototype` directly.
    ```javascript
    // bad
    function Harvest(fields = []) {
      this.queue = [...fields];
    }

    Harvest.prototype.yieldCrop = function () {
      const crop = this.queue[0];
      this.queue.splice(0, 1);
      return crop;
    };

    // good
    class Harvest {
      constructor(fields = []) {
        this.queue = [...fields];
      }

      yieldCrop() {
        const crop = this.queue[0];
        this.queue.splice(0, 1);
        return crop;
      }
    }
    ```

  <a name="constructors--extends"></a>
  - [8.2](#constructors--extends) Use `extends` for inheritance.

    ```javascript
    // good
    class WalnutOrchard extends Orchard {
      // ...
    }
    ```

  <a name="constructors--chaining"></a><a name="8.3"></a>
  - [8.3](#constructors--chaining) Methods can return `this` to help with method chaining.

    ```javascript
    // good
    class Field {
      water() {
        this.watering = true;
        return this;
      }

      fertilize(height) {
        this.fertilize = true;
        return this;
      }
    }

    const field = new Field();

    field.water()
      .fertilize();
    ```


**[⬆ back to top](#table-of-contents)**

### Modules

  <a name="modules--use-them"></a>
  - [9.1](#modules--use-them) Always use modules (`import`/`export`) over a non-standard module system. You can always transpile to your preferred module system.

    ```javascript
    // bad
    const HeavyEquipment = require('./HeavyEquipment');
    module.exports = HeavyEquipment.tractor;

    // best
    import { tractor } from './HeavyEquipment';
    export default tractor;
    ```

  <a name="modules--prefer-default-export"></a>
  - [9.2](#modules--prefer-default-export) In modules with a single export, prefer default export over named export.
    ```javascript
    // bad
    export function waterOrchard() {}

    // good
    export default function waterOrchard() {}
    ```

**[⬆ back to top](#table-of-contents)**

### Iterators and Generators

  <a name="iterators--nope"></a>
  - [10.1](#iterators--nope) Don’t use iterators. Prefer JavaScript’s higher-order functions instead of loops like `for-in` or `for-of`.

  Use `map()` / `every()` / `filter()` / `find()` / `findIndex()` / `reduce()` / `some()` / ... to iterate over arrays, and `Object.keys()` / `Object.values()` / `Object.entries()` to produce arrays so you can iterate over objects.

    ```javascript
    const numbers = [1, 2, 3, 4, 5];

    // bad
    let allVeggies = 0;
    for (let number of numbers) {
      allVeggies += number;
    }

    // good
    let allVeggies = 0;
    numbers.forEach((number) => {
      allVeggies += number;
    });

    // best
    const allVeggies = numbers.reduce((total, number) => total += number, 0);
    ```

**[⬆ back to top](#table-of-contents)**

### Properties

  <a name="properties--dot"></a>
  - [11.1](#properties--dot) Use dot notation when accessing properties.

    ```javascript
    const oldMcDonald = {
      farm: true,
      age: 88,
    };

    // bad
    const hasFarm = oldMcDonald['farm'];

    // good
    const hasFarm = oldMcDonald.farm;
    ```

  <a name="properties--bracket"></a>
  - [11.2](#properties--bracket) Use bracket notation `[]` when accessing properties with a variable.

    ```javascript
    const oldMcDonald = {
      farm: true,
      age: 88,
    };

    function getProp(prop) {
      return oldMcDonald[prop];
    }

    const hasFarm = getProp('farm');
    ```

**[⬆ back to top](#table-of-contents)**

### Variables

  <a name="variables--const-let-group"></a><a name="11.1"></a>
  - [12.1](#variables--const-let-group) Group all your `const`s and then group all your `let`s.
    ```javascript
    // bad
    let i;
    const fruits = getFruits();
    let bestFruit;
    const isFarmer = true;
    let totalFruits;

    // good
    const isFarmer = true;
    const fruits = getFruits();
    let bestFruit;
    let i;
    let totalFruits;
    ```

  <a name="variables--define-where-used"></a>
  - [12.2](#variables--define-where-used) Assign variables where you need them, but place them in a reasonable location.
    ```javascript
    // bad
    function checkFruitName(fruitName) {
      const name = getName();

      if (fruitName === 'test') {
        return false;
      }

      if (name === 'test') {
        this.setName('');
        return false;
      }

      return name;
    }

    // good
    function checkFruitName(fruitName) {
      if (fruitName === 'test') {
        return false;
      }

      const name = getName();

      if (name === 'test') {
        this.setName('');
        return false;
      }

      return name;
    }
    ```

  <a name="variables--unary-increment-decrement"></a>
  - [12.3](#variables--unary-increment-decrement) Avoid using unary increments and decrements (`++`, `--`) as they are subject to automatic semicolon insertion and can cause silent errors with incrementing or decrementing values within an application.
    ```javascript
    // bad
    let totalHarvest = 1;
    totalHarvest++;
    --totalHarvest;

    // good
    let totalHarvest = 1;
    totalHarvest += 1;
    totalHarvest -= 1;
    ```

**[⬆ back to top](#table-of-contents)**


### Comparison Operators & Equality

  <a name="comparison--if"></a>
  - [12.1](#comparison--if) Conditional statements such as the `if` statement evaluate their expression using coercion with the `ToBoolean` abstract method and always follow these simple rules:

    - **Objects** evaluate to **true**
    - **Undefined** evaluates to **false**
    - **Null** evaluates to **false**
    - **Booleans** evaluate to **the value of the boolean**
    - **Numbers** evaluate to **false** if **+0, -0, or NaN**, otherwise **true**
    - **Strings** evaluate to **false** if an empty string `''`, otherwise **true**

    ```javascript
    if ([0] && []) {
      // true
      // an array (even an empty one) is an object, objects will evaluate to true
    }
    ```

  <a name="comparison--shortcuts"></a><a name="12.2"></a>
  - [12.2](#comparison--shortcuts) Use shortcuts for booleans, but explicit comparisons for strings and numbers.

    ```javascript
    // bad
    if (isVeggie === true) {
      // ...
    }

    // good
    if (isVeggie) {
      // ...
    }

    // bad
    if (fruitName) {
      // ...
    }

    // good
    if (fruitName !== '') {
      // ...
    }

    // bad
    if (cropsHarvested.length) {
      // ...
    }

    // good
    if (cropsHarvested.length > 0) {
      // ...
    }
    ```

  <a name="comparison--switch-blocks"></a>
  - [12.3](#comparison--switch-blocks) Use braces to create blocks in `case` and `default` clauses that contain lexical declarations (e.g. `let`, `const`, `function`, and `class`).
    ```javascript
    // bad
    switch (crop) {
      case 'walnut':
        let price = 1;
        break;
      case 'squash':
        const price = 2;
        break;
      case 'carrot':
        function countCarrots() {
          // ...
        }
        break;
      default:
        class Fruit {}
    }

    // good
    switch (crop) {
      case 'walnut': {
        let price = 1;
        break;
      }
      case 'squash': {
        const price = 2;
        break;
      }
      case 'carrot': {
        function countCarrots() {
          // ...
        }
        break;
      }
      default: {
        class Fruit {}
      }
    }
    ```

  <a name="comparison--nested-ternaries"></a>
  - [12.4](#comparison--nested-ternaries) Ternaries should not be nested and generally be single line expressions.

    ```javascript
    // good
    const typeOfHarvest = name === 'tomato'
      ? 'fruit'
      : 'veggie';

    // best
    const typeOfHarvest = name === 'tomato' ? 'fruit' : 'veggie';
    ```

**[⬆ back to top](#table-of-contents)**

### Blocks

  <a name="blocks--braces"></a>
  - [13.1](#blocks--braces) Use braces with all multi-line blocks.

    ```javascript
    // bad
    if (farmer)
      return false;

    // good
    if (farmer) {
      return false;
    }
    ```

  <a name="blocks--cuddled-elses"></a><a name="13.2"></a>
  - [13.2](#blocks--cuddled-elses) If you’re using multi-line blocks with `if` and `else`, put `else` on the same line as your `if` block’s closing brace.

    ```javascript
    // bad
    if (farmer) {
      rideTractor();
    }
    else {
      rideBus();
    }

    // good
    if (test) {
      rideTractor();
    } else {
      rideBus();
    }
    ```

  <a name="blocks--no-else-return"></a><a name="16.3"></a>
  - [13.3](#blocks--no-else-return) If an `if` block always executes a `return` statement, the subsequent `else` block is unnecessary. A `return` in an `else if` block following an `if` block that contains a `return` can be separated into multiple `if` blocks.

    ```javascript
    // bad
    function checkType(crop) {
      if (crop.isFruit) {
        return 'Fruit';
      } else {
        return 'Veggie';
      }
    }

    // good
    function checkType(crop) {
      if (crop.isFruit) {
        return 'Fruit';
      }

      return 'Veggie';
    }

    // bad
    function takeMeal() {
      if (lunch) {
        return 'Get yer lunch';
      } else if (dinner) {
        return 'Get yer dinner';
      }
    }

    // good
    function takeMeal() {
      if (lunch) {
        return 'Get yer lunch';
      }

      if (dinner) {
        return 'Get yer dinner';
      }
    }

    ```

**[⬆ back to top](#table-of-contents)**

### Control Statements

  <a name="control-statements"></a>
  - [14.1](#control-statements) In case your control statement (`if`, `while` etc.) gets too long or exceeds the maximum line length, each (grouped) condition could be put into a new line. The logical operator should begin the line.
    ```javascript
    // bad
    if ((totalVeggies === 999 || period === 'evening') && theTractorNeedsRepair() && theFarmerNeedsSomeHelp()) {
      retireForTheEvening();
    }

    // good
    if (
      (totalVeggies === 999 || period === 'evening')
      && theTractorNeedsRepair()
      && theFarmerNeedsSomeHelp()
    ) {
      retireForTheEvening();
    }
    ```

  <a name="control-statement--value-selection"></a>
  - [14.2](#control-statements--value-selection) Don't use selection operators in place of control statements.

    ```javascript
    // bad
    !isEvening && waterThemFields();

    // good
    if (!isEvening) {
      waterThemFields();
    }
    ```

**[⬆ back to top](#table-of-contents)**

### Comments

  <a name="comments--actionitems"></a>
  - [15.1](#comments--actionitems) Prefixing your comments with `FIXME` or `TODO` helps other developers quickly understand if you’re pointing out a problem that needs to be revisited, or if you’re suggesting a solution to the problem that needs to be implemented. These are different than regular comments because they are actionable. The actions are `FIXME: -- need to figure this out` or `TODO: -- need to implement`.

  <a name="comments--fixme"></a><a name="15.2"></a>
  - [15.2](#comments--fixme) Use `// FIXME:` to annotate problems.

    ```javascript
    class WalnutOrchard extends Orchard {
      constructor() {
        super();

        // FIXME: shouldn’t use a global here
        totalYield = 0;
      }
    }
    ```

  <a name="comments--todo"></a><a name="15.3"></a>
  - [15.3](#comments--todo) Use `// TODO:` to annotate solutions to problems.

    ```javascript
    class WalnutOrchard extends Orchard {
      constructor() {
        super();

        // TODO: total should be configurable by an options param
        this.totalYield = 0;
      }
    }
    ```

**[⬆ back to top](#table-of-contents)**

### Commas

  <a name="commas--leading-trailing"></a>
  - [16.1](#commas--leading-trailing) Use trailing commas for multiline `arrays`, `objects`, `imports`, `exports` and `functions`.

    ```javascript
    // bad
    const veggies = [
      'carrots',
      'celery',
      'tomato'
    ];

    // good
    const veggies = [
      'carrots',
      'celery',
      'tomato',
    ];

    // bad
    const farmer = {
      firstName: 'Mark',
      lastName: 'McDonald',
      birthYear: 1957
    };

    // good
    const farmer = {
      firstName: 'Mark',
      lastName: 'McDonald',
      birthYear: 1957,
    };
    ```

**[⬆ back to top](#table-of-contents)**

### Semicolons

  <a name="semicolons--required"></a>
  - [17.1](#semicolons--required) Use semicolons to terminate all statements because ASI is not reliable.
    ```javascript

    // bad - returns `undefined`
    function wakeBeforeDawn() {
      return
        'Early bird gets the worm'
    }

    // good
    function wakeBeforeDawn() {
      return 'Early bird gets the worm';
    }
    ```

**[⬆ back to top](#table-of-contents)**

### Type Casting & Coercion

  <a name="coercion--strings"></a>
  - [18.1](#coercion--strings) Strings
    ```javascript
    // bad
    const totalYield = this.cropYield.toString(); // isn’t guaranteed to return a string

    // bad
    const totalYield = new String(this.cropYield); // returns an object

    // good
    const totalYield = String(this.cropYield);
    ```

  <a name="coercion--numbers"></a>
  - [18.2](#coercion--numbers) Numbers: Use `Number` for type casting and `parseInt` always with a radix for parsing strings.

    ```javascript
    const totalAcres = '4';

    // bad
    const farmSize = new Number(totalAcres);

    // good
    const farmSize = Number(totalAcres);

    // bad
    const farmSize = parseInt(totalAcres);

    // good
    const farmSize = parseInt(totalAcres, 10);
    ```
  <a name="coercion--booleans"></a><a name="18.5"></a>
  - [18.3](#coercion--booleans) Boolean

    ```javascript
    const totalYield = 0;

    // bad
    const hasCrop = new Boolean(totalYield);

    // good
    const hasCrop = Boolean(totalYield);

    // best
    const hasCrop = !!totalYield;
    ```

**[⬆ back to top](#table-of-contents)**

### Accessors

  <a name="accessors--no-getters-setters"></a>
  - [19.1](#accessors--no-getters-setters) Do not use JavaScript getters/setters as they cause unexpected side effects and are harder to test, maintain, and reason about. Instead, if you do make accessor functions, use `getVal()` and `setVal('hello')`.

    ```javascript
    // bad
    class Orchard {
      get type() {
        // ...
      }

      set type(value) {
        // ...
      }
    }

    // good
    class Orchard {
      getType() {
        // ...
      }

      setType(value) {
        // ...
      }
    }
    ```


**[⬆ back to top](#table-of-contents)**

---
_Source: https://npm.io/package/se-javascript-style-guide · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
