eslint-config-throtinstudio

Styleguide javascript de Throrinstudio


Keywords
eslint, styleguide
License
MIT
Install
npm install eslint-config-throtinstudio@1.0.0

Documentation

Throrinstudio Javascript Styleguide

Table of Content

Installation

Backend

npm install -DE eslint eslint-config-throrinstudio

# or
yarn add -D eslint eslint-config-throrinstudio

Utilisation

Plusieurs choix s'ouvrent à vous en fonction du type de projet utilisé. Vous devrez, pour chacun créer le fichier .eslintrc.* de la façon suivante :

  • Projets Node.JS :

    module.exports = {
        extends: ["eslint:recommended", "throrinstudio"],
    };
  • Projets VueJS 2.0 (si build avec webpack et babel) :

    module.exports = {
        extends: [
            "eslint:recommended",
            "plugin:vue/recommended",
            // à appeler en dernier pour bien prendre les surcharges du plugin vue
            "throrinstudio/vue",
        ],
    };

Remarque : Pour chacune de ces extensions, les règles sont identiques. Il s'agit juste des différents plugins supplémentaires qui sont ou non rajoutés. Ne vous en faites pas, ce module les installe pour vous.

Types

  • Primitives : Quand vous accédez à un type primitif, vous modifiez directement la variable.

    • string
    • number
    • boolean
    • null
    • undefined
    const foo = 1;
    let bar = foo;
    
    bar = 9;
    
    console.log(foo, bar); // => 1, 9
  • Complexe : Quand vous accédez à un type complexe, vous travaillez directement sur la référence.

    • object
    • array
    • function
    const foo = [1, 2];
    const bar = foo;
    
    bar[0] = 9;
    
    console.log(foo[0], bar[0]); // => 9, 9

References

  • Utilisez const pour toutes vos références. N'utilisez pas var. eslint: prefer-const, no-const-assign

    Cela permet de ne pas réassigner vos références par mégarde et ainsi éviter des bugs tout en améliorant la compréhension de votre code.

    // bad
    var a = 1;
    var b = 2;
    
    // good
    const a = 1;
    const b = 2;
  • Si vous comptez réassigner une référence, utilisez let à la place de var. eslint: no-var

    let est "block-scoped" alors que var est "function-scopped"

    // bad
    var count = 1;
    if (true) {
        count += 1;
    }
    
    // good, use the let.
    let count = 1;
    if (true) {
        count += 1;
    }
  • Important : let et const sont "block-scopped" :

    // const and let only exist in the blocks they are defined in.
    {
        let a = 1;
        const b = 1;
    }
    console.log(a); // ReferenceError
    console.log(b); // ReferenceError

Objects

  • Utilisez la syntaxe littérale pour la créatopn des objets. eslint: no-new-object

    // bad
    const item = new Object();
    
    // good
    const item = {};
  • Utilisez les "computed property names" quand vous créez un objet avec des propriétés dynamiques.

    Ceci permet de définir votre objet en une seule fois

    function getKey(k) {
        return `a key named ${k}`;
    }
    
    // bad
    const obj = {
        id: 5,
        name: "San Francisco",
    };
    obj[getKey("enabled")] = true;
    
    // good
    const obj = {
        id: 5,
        name: "San Francisco",
        [getKey("enabled")]: true,
    };
  • Utilisez les méthodes d'objet raccourcies. eslint: object-shorthand

    // bad
    const atom = {
        value: 1,
        addValue: function (value) {
            return atom.value + value;
        },
    };
    
    // good
    const atom = {
        value: 1,
        addValue(value) {
            return atom.value + value;
        },
    };
  • Utilisez les valeurs raccourcies. eslint: object-shorthand

    C'est plus court à écrire et suffit amplement à la compréhension du code.

    const lukeSkywalker = "Luke Skywalker";
    
    // bad
    const obj = {
        lukeSkywalker: lukeSkywalker,
    };
    
    // good
    const obj = {
        lukeSkywalker,
    };
  • Groupes toutes vos propriétés raccourcies à la fin de votre objet :

    Cela permet de savoir facilement quelles propriétés sont des propriétés raccourcies.

    const anakinSkywalker = "Anakin Skywalker";
    const lukeSkywalker = "Luke Skywalker";
    
    // bad
    const obj = {
        episodeOne: 1,
        twoJediWalkIntoACantina: 2,
        lukeSkywalker,
        episodeThree: 3,
        mayTheFourth: 4,
        anakinSkywalker,
    };
    
    // good
    const obj = {
        episodeOne: 1,
        twoJediWalkIntoACantina: 2,
        episodeThree: 3,
        mayTheFourth: 4,
        lukeSkywalker,
        anakinSkywalker,
    };
  • Utilisez uniquement les quotes sur les noms de fields si leur nom est invalide sans. eslint: quote-props

    En général, on considère ceci simplement plus facile à lire. Ça améliore le syntax highlighting, et c'est surtout plus optimisé par plusieurs moteurs JS.

    // bad
    const bad = {
        foo: 3,
        bar: 4,
        "data-blah": 5,
    };
    
    // good
    const good = {
        foo: 3,
        bar: 4,
        "data-blah": 5,
    };
  • Préférez l'opérateur spread au lieu de Object.assign pour copier des objets. Utilisez l'opérateur rest pour récupérer un nouvel objet en omettant certaines propriétés.

    // very bad
    const original = { a: 1, b: 2 };
    const copy = Object.assign(original, { c: 3 }); // this mutates `original` ಠ_ಠ
    delete copy.a; // so does this
    
    // bad
    const original = { a: 1, b: 2 };
    const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 }
    
    // good
    const original = { a: 1, b: 2 };
    const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }
    
    const { a, ...noA } = copy; // noA => { b: 2, c: 3 }

Arrays

  • Utilisez la syntaxe littérale pour la créatopn des arrays. eslint: no-array-constructor

    // bad
    const items = new Array();
    
    // good
    const items = [];
  • Utilisez Array#push plutôt que d'ajouter directement une valeur à votre tableau.

    const someStack = [];
    
    // bad
    someStack[someStack.length] = "abracadabra";
    
    // good
    someStack.push("abracadabra");
  • Utilisez le spread operator ... pour copier des tableaux.

    // bad
    const len = items.length;
    const itemsCopy = [];
    let i;
    
    for (i = 0; i < len; i += 1) {
        itemsCopy[i] = items[i];
    }
    
    // good
    const itemsCopy = [...items];
  • Pour convertir un array-like objet en array, utilisez Array.from.

    const foo = document.querySelectorAll(".foo");
    const nodes = Array.from(foo);
  • Utilisez un return statement dans les callbacks des méthodes d'array. Il est possible de ne pas le mettre si le contenu de la fonction peut se faire en un seul traitement. eslint: array-callback-return

    // good
    [1, 2, 3].map((x) => {
        const y = x + 1;
        return x * y;
    });
    
    // good
    [1, 2, 3].map((x) => x + 1);
    
    // bad
    const flat = {};
    [
        [0, 1],
        [2, 3],
        [4, 5],
    ].reduce((memo, item, index) => {
        const flatten = memo.concat(item);
        flat[index] = flatten;
    });
    
    // good
    const flat = {};
    [
        [0, 1],
        [2, 3],
        [4, 5],
    ].reduce((memo, item, index) => {
        const flatten = memo.concat(item);
        flat[index] = flatten;
        return flatten;
    });
    
    // bad
    inbox.filter((msg) => {
        const { subject, author } = msg;
        if (subject === "Mockingbird") {
            return author === "Harper Lee";
        } else {
            return false;
        }
    });
    
    // good
    inbox.filter((msg) => {
        const { subject, author } = msg;
        if (subject === "Mockingbird") {
            return author === "Harper Lee";
        }
    
        return false;
    });

Destructuring

  • Utilisez les objects destructuring si vous voulez accéder et utiliser plusieures propriétés d'un objet.

    Le destructuring vous permet de ne pas créer des références pour ces propriétés.

    // bad
    function getFullName(user) {
        const firstName = user.firstName;
        const lastName = user.lastName;
    
        return `${firstName} ${lastName}`;
    }
    
    // good
    function getFullName(user) {
        const { firstName, lastName } = user;
        return `${firstName} ${lastName}`;
    }
    
    // best
    function getFullName({ firstName, lastName }) {
        return `${firstName} ${lastName}`;
    }
  • Utilisez les array destructuring

    const arr = [1, 2, 3, 4];
    
    // bad
    const first = arr[0];
    const second = arr[1];
    
    // good
    const [first, second] = arr;
  • Utilisez l'object destructuring pour retourner plusieures valeurs, pas l'array destructuring.

    Vous pouvez ajouter de nouvelles propriétés ou changer l'ordre des éléments sans casser les différents appels.

    // bad
    function processInput(input) {
        // then a miracle occurs
        return [left, right, top, bottom];
    }
    
    // the caller needs to think about the order of return data
    const [left, __, top] = processInput(input);
    
    // good
    function processInput(input) {
        // then a miracle occurs
        return { left, right, top, bottom };
    }
    
    // the caller selects only the data they need
    const { left, top } = processInput(input);

Strings

  • Utilisez les simples quotes '' pour les strings. eslint: quotes

    // bad
    const name = "Capt. Janeway";
    
    // bad - template literals should contain interpolation or newlines
    const name = `Capt. Janeway`;
    
    // good
    const name = "Capt. Janeway";
  • Les Strings qui font que la ligne dépasse les 100 caractères ne dois plus être écrite sur plusieurs lignes utilisant les concaténations.

    Les strings cassés en plusieurs parties compliquent les recherches et le travail avec.

    // bad
    const errorMessage =
        "This is a super long error that was thrown because \
    of Batman. When you stop to think about how Batman had anything to do \
    with this, you would get nowhere \
    fast.";
    
    // bad
    const errorMessage =
        "This is a super long error that was thrown because " +
        "of Batman. When you stop to think about how Batman had anything to do " +
        "with this, you would get nowhere fast.";
    
    // good
    const errorMessage =
        "This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.";
  • Lors de la création de strings utilisant des variables, utilisez les templates de Strings 9ES6) au lieu de la concaténation. eslint: prefer-template template-curly-spacing

    Les templates vous permettent d'avoir des strings lisibles facilement, une syntaxe propre avec de vrais sauts de ligne quand vous en voulez ainsi que la feature d'interpolations de variables.

    // bad
    function sayHi(name) {
        return "How are you, " + name + "?";
    }
    
    // bad
    function sayHi(name) {
        return ["How are you, ", name, "?"].join();
    }
    
    // bad
    function sayHi(name) {
        return `How are you, ${name}?`;
    }
    
    // good
    function sayHi(name) {
        return `How are you, ${name}?`;
    }
  • Ne jamais utiliser la commande eval(). eslint no-eval

  • Ne pas nécessairement échapper des caractères dans les Strings. eslint: no-useless-escape

    Les Backslashes compliquent la lecture. Ils ne doivent uniquement être présents par nécessité.

    // bad
    const foo = "'this' is \"quoted\"";
    
    // good
    const foo = "'this' is \"quoted\"";
    const foo = `my name is '${name}'`;

Functions

  • Utilisez les expressions de fonctions au lieux des déclarations de fonction. eslint: func-style

    Les déclarations de fonctions sont hissées (déclarées en premier, avant n'importe quelle variable, ...). Il est donc facile - trop facile - de référencer cette fonction avant de la définir dans le fichier. Ceci complique fortement la lecture et la maintenabilité du code. N'oubliez surtout pas de nommer vos fonctions. Des fonctions anonymes compliquent le debug avec le résultat d'une callstack d'erreur. Si votre fonction devient trop compliquée et trop "grosse", vous devez peut-être la sortir de votre fichier actuel pour en faire un module à part entière.

    // bad
    function foo() {
        // ...
    }
    
    // bad
    const foo = function () {
        // ...
    };
    
    // good
    const foo = function bar() {
        // ...
    };
  • Wrappez les fonctions appelées immédiatement entre parenthèses. eslint: wrap-iife

    Une expression de fonction immédiatement appelée est une unité unique - l'enveloppant à la fois elle et ses parenthèses d'invocation, entre parenthèses, l'exprime clairement. Notez que dans un monde avec des modules partout, vous n'avez presque jamais besoin d'un IIFE.

    // immediately-invoked function expression (IIFE)
    (function () {
        console.log("Welcome to the Internet. Please follow me.");
    })();
  • Ne jamais déclarer une fonction dans un block non fonctionnel (if, while, ...). Assignez votre fonction à une variable à la place. eslint: no-loop-func

  • Note : ECMA-262 définit un "block" comme une liste de différents statements. Une déclaration de fonction n'est en aucun cas un statement. Read ECMA-262's note on this issue.

    // bad
    if (currentUser) {
        function test() {
            console.log("Nope.");
        }
    }
    
    // good
    let test;
    if (currentUser) {
        test = () => {
            console.log("Yup.");
        };
    }
  • Ne jamais appeler un paramètre de fonctions arguments. Ceci peut ammener des confusions ou des problèmes avec l'objet arguments disponible dans le scope de chaque fonction.

    // bad
    function foo(name, options, arguments) {
        // ...
    }
    
    // good
    function foo(name, options, args) {
        // ...
    }
  • Au lieu d'utiliser l'objet arguments, il est mieux et plus simple de passer par l'opérateur .... eslint: prefer-rest-params

    ... est beaucoup plus explicite pour les arguments que vous pouvez rajouter dans une fonction. De plus les arguments récupérés avec forment un véritable Array.

    // bad
    function concatenateAll() {
        const args = Array.prototype.slice.call(arguments);
        return args.join("");
    }
    
    // good
    function concatenateAll(...args) {
        return args.join("");
    }
  • Utilisez les paramètres par défaut plutôt que de faire du mutating.

    // really bad
    function handleThings(opts) {
        // No! We shouldn't mutate function arguments.
        // Double bad: if opts is falsy it'll be set to an object which may
        // be what you want but it can introduce subtle bugs.
        opts = opts || {};
        // ...
    }
    
    // still bad
    function handleThings(opts) {
        if (opts === void 0) {
            opts = {};
        }
        // ...
    }
    
    // good
    function handleThings(opts = {}) {
        // ...
    }
  • Évitez les effets de bord avec les paramètres par défaut

    var b = 1;
    // bad
    function count(a = b++) {
        console.log(a);
    }
    count(); // 1
    count(); // 2
    count(3); // 3
    count(); // 3
  • Toujours mettre les paramêtres par défaut en dernier

    // bad
    function handleThings(opts = {}, name) {
        // ...
    }
    
    // good
    function handleThings(name, opts = {}) {
        // ...
    }
  • Ne jamais utiliser le constructeur Function pour créer une nouvelle fonction. eslint: no-new-func

    Créer une fonction par cette méthode évalue la String de ma même manière que le eval().

    // bad
    var add = new Function("a", "b", "return a + b");
    
    // still bad
    var subtract = Function("a", "b", "return a - b");
  • Espacement dans les signatures de fonction. eslint: space-before-function-paren space-before-blocks

    La cohérence est bonne, et vous ne devriez pas avoir à ajouter ou supprimer un espace lors de l'ajout ou la suppression d'un nom.

    // bad
    const f = function () {};
    const g = function () {};
    const h = function () {};
    
    // good
    const x = function () {};
    const y = function a() {};
  • Ne jamais surcharger des paramètres. Remarque : Cette limitation est désactivée pour les fonctions map, filter, et autres Promesses.

    Réassigner des paramètres peut causer des effets de bord avec la stack appelante.

    // bad
    function f1(obj) {
        obj.key = 1;
    }
    
    // good
    function f2(obj) {
        const key = Object.prototype.hasOwnProperty.call(obj, "key")
            ? obj.key
            : 1;
    }
  • Ne jamais réassigner des paramètres.

    Réassigner des paramètres peut causer des effets de bord surtout si vous accédez à l'objet arguments. Cela peut aussi causer des soucis d'optimisation. Surtout en V8.

    // bad
    function f1(a) {
        a = 1;
        // ...
    }
    
    function f2(a) {
        if (!a) {
            a = 1;
        }
        // ...
    }
    
    // good
    function f3(a) {
        const b = a || 1;
        // ...
    }
    
    function f4(a = 1) {
        // ...
    }
  • Préférez l'utilisation du spread operator ... pour appeler des fonctions avec un nombre de paramètres variables. eslint: prefer-spread

    C'est plus propre, vous n'avez pas à spécifier le contexte et vous n'avez pas à coupler un new avec apply.

    // bad
    const x = [1, 2, 3, 4, 5];
    console.log.apply(console, x);
    
    // good
    const x = [1, 2, 3, 4, 5];
    console.log(...x);
    
    // bad
    new (Function.prototype.bind.apply(Date, [null, 2016, 8, 5]))();
    
    // good
    new Date(...[2016, 8, 5]);
  • Les fonctions avec des signatures, ou invications, sur plusieurs lignes doivent êtres indentées comme toute autre liste dans ce guide : Avec chaque item sur une nouvelle ligne et une , en fin de ligne, y compris sur la dernière.

    // bad
    function foo(bar, baz, quux) {
        // ...
    }
    
    // good
    function foo(bar, baz, quux) {
        // ...
    }
    
    // bad
    console.log(foo, bar, baz);
    
    // good
    console.log(foo, bar, baz);
  • Il est interdit d'avoir du code après des return, throw, continue, et break. eslint : no-unreachable

    // bad
    function foo() {
        return true;
        console.log("done");
    }
    
    function bar() {
        throw new Error("Oops!");
        console.log("done");
    }
    
    while (value) {
        break;
        console.log("done");
    }
    
    throw new Error("Oops!");
    console.log("done");
    
    function baz() {
        if (Math.random() < 0.5) {
            return;
        } else {
            throw new Error();
        }
        console.log("done");
    }
    
    for (;;) {}
    console.log("done");
    
    // good
    function foo() {
        return bar();
        function bar() {
            return 1;
        }
    }
    
    function bar() {
        return x;
        var x;
    }
    
    switch (foo) {
        case 1:
            break;
            var x;
    }

Arrow Functions

  • Quand vous devez passer par une expression de fonctions (quand vous passez une fonction anonyme), utilisez la notation de fonctions fléchées. eslint: prefer-arrow-callback, arrow-spacing

    Ça créer une version de la fonction utilisée dans le contexte this, qui est la plupart du temps ce que vous voulez (évite un bind(this))

    // bad
    [1, 2, 3].map(function (x) {
        const y = x + 1;
        return x * y;
    });
    
    // good
    [1, 2, 3].map((x) => {
        const y = x + 1;
        return x * y;
    });
  • Si le contenu de la fonction fléchée se résume à une seule expression, oubliez les accolades et utilisez le return implicite. Sinon, laissez les et utilisez un return statement. eslint: arrow-parens, arrow-body-style

    Sucre syntaxique. Il y a une meilleure lecture quand plusieurs fonctions sont enchaînées ensemble.

    // bad
    [1, 2, 3].map((number) => {
        const nextNumber = number + 1;
        `A string containing the ${nextNumber}.`;
    });
    
    // good
    [1, 2, 3].map((number) => `A string containing the ${number}.`);
    
    // good
    [1, 2, 3].map((number) => {
        const nextNumber = number + 1;
        return `A string containing the ${nextNumber}.`;
    });
    
    // good
    [1, 2, 3].map((number, index) => ({
        [index]: number,
    }));
  • Dans le cas où l'expression s'étend sur plusieurs lignes, l'envelopper entre parenthèses pour une meilleure lisibilité.

    Elles indiquent clairement où commence et se termine la fonction.

    // bad
    ["get", "post", "put"].map((httpMethod) =>
        Object.prototype.hasOwnProperty.call(
            httpMagicObjectWithAVeryLongName,
            httpMethod
        )
    );
    
    // good
    ["get", "post", "put"].map((httpMethod) =>
        Object.prototype.hasOwnProperty.call(
            httpMagicObjectWithAVeryLongName,
            httpMethod
        )
    );
  • Si votre fonction prend un seul argument et n'utilise pas d'accolades, omettez les parenthèses. Sinon, incluez toujours des parenthèses autour des arguments pour plus de clarté et de cohérence. Remarque: il est également acceptable de toujours utiliser des parenthèses. Dans ce cas, utilisez l'option "always" option pour eslint. eslint: arrow-parens

    Pourquoi ? Moins d'encombrement visuel.

    // bad
    [1, 2, 3].map((x) => x * x);
    
    // good
    [1, 2, 3].map((x) => x * x);
    
    // good
    [1, 2, 3].map(
        (number) =>
            `A long string with the ${number}. It’s so long that we don’t want it to take up space on the .map line!`
    );
    
    // bad
    [1, 2, 3].map((x) => {
        const y = x + 1;
        return x * y;
    });
    
    // good
    [1, 2, 3].map((x) => {
        const y = x + 1;
        return x * y;
    });
  • Évitez de confondre la syntaxe de la fonction fléchée (=>) avec les opérateurs de comparaison (<=, >=). eslint: no-confusing-arrow

    // bad
    const itemHeight = (item) =>
        item.height > 256 ? item.largeSize : item.smallSize;
    
    // bad
    const itemHeight = (item) =>
        item.height > 256 ? item.largeSize : item.smallSize;
    
    // good
    const itemHeight = (item) =>
        item.height > 256 ? item.largeSize : item.smallSize;
    
    // good
    const itemHeight = (item) => {
        const { height, largeSize, smallSize } = item;
        return height > 256 ? largeSize : smallSize;
    };

Classes et Constructeurs

  • Toujours utiliser class. Évitez de manipuler prototype directement.

    La syntaxe class est plus concise et plus facile à raisonner.

    // bad
    function Queue(contents = []) {
        this.queue = [...contents];
    }
    Queue.prototype.pop = function () {
        const value = this.queue[0];
        this.queue.splice(0, 1);
        return value;
    };
    
    // good
    class Queue {
        constructor(contents = []) {
            this.queue = [...contents];
        }
        pop() {
            const value = this.queue[0];
            this.queue.splice(0, 1);
            return value;
        }
    }
  • Utilisez extends pour les héritages

    Il s'agit d'un moyen intégré d'hériter des fonctionnalités de prototype sans casser instanceof.

    // bad
    const inherits = require("inherits");
    function PeekableQueue(contents) {
        Queue.apply(this, contents);
    }
    inherits(PeekableQueue, Queue);
    PeekableQueue.prototype.peek = function () {
        return this.queue[0];
    };
    
    // good
    class PeekableQueue extends Queue {
        peek() {
            return this.queue[0];
        }
    }
  • Les méthodes peuvent retourner this pour faciliter le chaînage des méthodes.

    // bad
    Jedi.prototype.jump = function () {
        this.jumping = true;
        return true;
    };
    
    Jedi.prototype.setHeight = function (height) {
        this.height = height;
    };
    
    const luke = new Jedi();
    luke.jump(); // => true
    luke.setHeight(20); // => undefined
    
    // good
    class Jedi {
        jump() {
            this.jumping = true;
            return this;
        }
    
        setHeight(height) {
            this.height = height;
            return this;
        }
    }
    
    const luke = new Jedi();
    
    luke.jump().setHeight(20);
  • Il est normal d'écrire une méthode personnalisée toString (), il suffit de s'assurer de son bon fonctionnement et qu'elle ne provoque aucun effet secondaire.

    class Jedi {
        constructor(options = {}) {
            this.name = options.name || "no name";
        }
    
        getName() {
            return this.name;
        }
    
        toString() {
            return `Jedi - ${this.getName()}`;
        }
    }
  • Les classes ont un constructeur par défaut s'il n'est pas spécifié. Une fonction de constructeur vide ou une déléguée à une classe parente est inutile. eslint: no-useless-constructor

    // bad
    class Jedi {
        constructor() {}
    
        getName() {
            return this.name;
        }
    }
    
    // bad
    class Rey extends Jedi {
        constructor(...args) {
            super(...args);
        }
    }
    
    // good
    class Rey extends Jedi {
        constructor(...args) {
            super(...args);
            this.name = "Rey";
        }
    }
  • Évitez les doublons. eslint: no-dupe-class-members

    Lors d'une déclaration de membres de classes en double, la classe préfèrera la dernière saisie.

    // bad
    class Foo {
        bar() {
            return 1;
        }
        bar() {
            return 2;
        }
    }
    
    // good
    class Foo {
        bar() {
            return 1;
        }
    }
    
    // good
    class Foo {
        bar() {
            return 2;
        }
    }

Modules (uniquement pour projets Front pour le moment)

  • Utilisez toujours des modules (import / export) sur un système de modules non standard. Vous pouvez toujours transpiler vers votre système de module préféré.

    Les modules sont l'avenir, commençons à utiliser l'avenir maintenant. Et puis ce sont surtout les nouveaux standards ES6

    // bad
    const AirbnbStyleGuide = require('./AirbnbStyleGuide');
    module.exports = AirbnbStyleGuide.es6;
    
    // ok
    import AirbnbStyleGuide from './AirbnbStyleGuide';
    export default AirbnbStyleGuide.es6;
    
    // best
    import { es6 } from './AirbnbStyleGuide';
    export default es6;
  • N'utilisez pas les wildcards import

    Cela garantit une exportation par défaut.

    // bad
    import * as AirbnbStyleGuide from "./AirbnbStyleGuide";
    
    // good
    import AirbnbStyleGuide from "./AirbnbStyleGuide";
  • Et n'exportez pas directement d'un import

    Bien que le one-liner soit concis, le fait d'avoir un moyen clair d'importer et un moyen clair d'exporter rend les choses cohérentes.

    // bad
    // filename es6.js
    export { es6 as default } from './AirbnbStyleGuide';
    
    // good
    // filename es6.js
    import { es6 } from './AirbnbStyleGuide';
    export default es6;
  • Importez uniquement à partir d'un chemin/module en un seul endroit. eslint: no-duplicate-imports

    Avoir plusieurs lignes qui importent à partir du même chemin peut rendre le code plus difficile à maintenir.

    // bad
    import foo from "foo";
    // … some other imports … //
    import { named1, named2 } from "foo";
    
    // good
    import foo, { named1, named2 } from "foo";
    
    // good
    import foo, { named1, named2 } from "foo";
  • N'exportez pas de mutable bindings. eslint: import/no-mutable-exports

    // bad
    let foo = 3;
    export { foo };
    
    // good
    const foo = 3;
    export { foo };
  • Dans un module avec un seul export, préférez utiliser le default export plutôt qu'un export nommé. eslint: import/prefer-default-export

    // bad
    export function foo() {}
    
    // good
    export default function foo() {}
  • Mettez tous vos import avant n'importe quel autre statement. eslint: import/first

    Puisque les import sont hissés, les garder en début de fichier empêche un comportement bizarre.

    // bad
    import foo from "foo";
    foo.init();
    
    import bar from "bar";
    
    // good
    import foo from "foo";
    import bar from "bar";
    
    foo.init();
  • Interdire la syntaxe de Webpack dans les import. eslint: import/no-webpack-loader-syntax

    Si vous utilisez la syntaxe de Webpack dans l'import, vous couplez fortement votre code à ce builder. Il est plutôt conseillé de mettre en place les différents loaders dans webpack.config.js.

    // bad
    import fooSass from "css!sass!foo.scss";
    import barCss from "style!css!bar.css";
    
    // good
    import fooSass from "foo.scss";
    import barCss from "bar.css";

Iterators et Generators

  • N'utilisez pas d'itérateurs. Préférez les fonctions d'ordre supérieur de JavaScript plutôt que les boucles comme for-in ou for-of. eslint: no-iterator no-restricted-syntax

    Fait respecter nos règles sur les immutables. Traiter avec des fonctions pures qui retournent des valeurs est plus facile à comprendre et permet d'éviter de possibles effets de bord.

    Utiliser map() / every() / filter() / find() / findIndex () / reduce() / some() / ... pour itérer sur des tableaux , Et Object.keys() / Object.values() / Object.entries() pour produire des tableaux afin que vous puissiez itérer sur des objets.

    const numbers = [1, 2, 3, 4, 5];
    
    // bad
    let sum = 0;
    for (let num of numbers) {
        sum += num;
    }
    sum === 15;
    
    // good
    let sum = 0;
    numbers.forEach((num) => (sum += num));
    sum === 15;
    
    // best (use the functional force)
    const sum = numbers.reduce((total, num) => total + num, 0);
    sum === 15;
    
    // bad
    const increasedByOne = [];
    for (let i = 0; i < numbers.length; i++) {
        increasedByOne.push(numbers[i] + 1);
    }
    
    // good
    const increasedByOne = [];
    numbers.forEach((num) => increasedByOne.push(num + 1));
    
    // best (keeping it functional)
    const increasedByOne = numbers.map((num) => num + 1);
  • N'utilisez pas encore les générateurs Front uniquement.

    Ils ne peuvent pas être convertis en ES5.

  • Si vous devez utiliser des générateurs, ou si vous négligez nos conseils, assurez-vous que la signature de fonction est espacée correctement. eslint: generator-star-spacing

    function et*font partie du même mot-clé conceptuel -*n'est pas un modificateur pour function, function* est une construction unique, différente de function.

    // bad
    function* foo() {
        // ...
    }
    
    // bad
    const bar = function* () {
        // ...
    };
    
    // bad
    const baz = function* () {
        // ...
    };
    
    // bad
    const quux = function* () {
        // ...
    };
    
    // bad
    function* foo() {
        // ...
    }
    
    // bad
    function* foo() {
        // ...
    }
    
    // very bad
    function* foo() {
        // ...
    }
    
    // very bad
    const wat = function* () {
        // ...
    };
    
    // good
    function* foo() {
        // ...
    }
    
    // good
    const foo = function* () {
        // ...
    };

Promesses

  • Ne pas d'exécuteurs async pour les promesses. eslint no-async-promise-executor

    // bad
    const result = new Promise(async (resolve, reject) => {
        readFile("foo.txt", function (err, result) {
            if (err) {
                reject(err);
            } else {
                resolve(result);
            }
        });
    });
    
    const result = new Promise(async (resolve, reject) => {
        resolve(await foo);
    });
    
    // good
    const result = new Promise((resolve, reject) => {
        readFile("foo.txt", function (err, result) {
            if (err) {
                reject(err);
            } else {
                resolve(result);
            }
        });
    });
    
    const result = Promise.resolve(foo);

Properties

  • Utiliser la notation par points pour accéder aux propriétés. eslint: dot-notation

    const luke = {
        jedi: true,
        age: 28,
    };
    
    // bad
    const isJedi = luke["jedi"];
    
    // good
    const isJedi = luke.jedi;
  • Utilisez la notation entre crochets [] pour accéder aux propriétés avec une variable.

    const luke = {
        jedi: true,
        age: 28,
    };
    
    function getProp(prop) {
        return luke[prop];
    }
    
    const isJedi = getProp("jedi");

Variables

  • Toujours utiliser const pour déclarer les variables. Si vous ne le faites pas, vous obtiendrez des variables globales. eslint: no-undef prefer-const

    // bad
    superPower = new SuperPower();
    
    // good
    const superPower = new SuperPower();
  • Utilisez une déclaration const par variable. eslint: one-var

    Il est plus facile d'ajouter de nouvelles déclarations de variables de cette façon et vous ne devez jamais vous préoccuper d'échanger un ; pour un , ou d'introduire des différences de ponctuation. Vous pouvez également parcourir chaque déclaration avec le débogueur, au lieu de sauter à travers tous les à la fois.

    // bad
    const items = getItems(),
        goSportsTeam = true,
        dragonball = "z";
    
    // bad
    // (compare to above, and try to spot the mistake)
    const items = getItems(),
        goSportsTeam = true;
    dragonball = "z";
    
    // good
    const items = getItems();
    const goSportsTeam = true;
    const dragonball = "z";
  • Groupez tous vos const et groupes tous vos let.

    C'est utile lorsque plus tard vous devrez peut-être affecter une variable en fonction de l'une des variables assignées précédemment.

    // bad
    let i,
        len,
        dragonball,
        items = getItems(),
        goSportsTeam = true;
    
    // bad
    let i;
    const items = getItems();
    let dragonball;
    const goSportsTeam = true;
    let len;
    
    // good
    const goSportsTeam = true;
    const items = getItems();
    let dragonball;
    let i;
    let length;
  • Attribuez des variables là où vous en avez besoin, mais placez-les dans un endroit raisonnable.

    • let et const sont des variables de block. Vous devrez les définir en fonction du block pouvant les utiliser.
    // bad - unnecessary function call
    function checkName(hasName) {
        const name = getName();
    
        if (hasName === "test") {
            return false;
        }
    
        if (name === "test") {
            this.setName("");
            return false;
        }
    
        return name;
    }
    
    // good
    function checkName(hasName) {
        if (hasName === "test") {
            return false;
        }
    
        const name = getName();
    
        if (name === "test") {
            this.setName("");
            return false;
        }
    
        return name;
    }
  • Ne chaînez pas les assignements de variable.

    Chaîner des assignements de variables créer des variables globales.

    // bad
    (function example() {
        // JavaScript interprets this as
        // let a = ( b = ( c = 1 ) );
        // The let keyword only applies to variable a; variables b and c become
        // global variables.
        let a = (b = c = 1);
    })();
    
    console.log(a); // undefined
    console.log(b); // 1
    console.log(c); // 1
    
    // good
    (function example() {
        let a = 1;
        let b = a;
        let c = a;
    })();
    
    console.log(a); // undefined
    console.log(b); // undefined
    console.log(c); // undefined
    
    // the same applies for `const`

Hoisting

  • la déclaration des var se trouve hissée au plus haut de son scope. Leur assignement non. les déclarations de const et let utilisent un nouveau concept appelé Temporal Dead Zones (TDZ). Il est important de savoir pourquoi typeof n'est plus sûr.

    // we know this wouldn't work (assuming there
    // is no notDefined global variable)
    function example() {
        console.log(notDefined); // => throws a ReferenceError
    }
    
    // creating a variable declaration after you
    // reference the variable will work due to
    // variable hoisting. Note: the assignment
    // value of `true` is not hoisted.
    function example() {
        console.log(declaredButNotAssigned); // => undefined
        var declaredButNotAssigned = true;
    }
    
    // the interpreter is hoisting the variable
    // declaration to the top of the scope,
    // which means our example could be rewritten as:
    function example() {
        let declaredButNotAssigned;
        console.log(declaredButNotAssigned); // => undefined
        declaredButNotAssigned = true;
    }
    
    // using const and let
    function example() {
        console.log(declaredButNotAssigned); // => throws a ReferenceError
        console.log(typeof declaredButNotAssigned); // => throws a ReferenceError
        const declaredButNotAssigned = true;
    }
  • Les expressions de fonction anonymes hissent leur nom de variable, mais pas l'assignement de fonction.

    function example() {
        console.log(anonymous); // => undefined
    
        anonymous(); // => TypeError anonymous is not a function
    
        var anonymous = function () {
            console.log("anonymous function expression");
        };
    }
  • Les expressions de fonction nommées hisser le nom de la variable, pas le nom de la fonction ou le corps de la fonction.

    function example() {
        console.log(named); // => undefined
    
        named(); // => TypeError named is not a function
    
        superPower(); // => ReferenceError superPower is not defined
    
        var named = function superPower() {
            console.log("Flying");
        };
    }
    
    // the same is true when the function name
    // is the same as the variable name.
    function example() {
        console.log(named); // => undefined
    
        named(); // => TypeError named is not a function
    
        var named = function named() {
            console.log("named");
        };
    }
  • Les déclarations de fonctions hissent leur nom et le corps de la fonction.

    function example() {
        superPower(); // => Flying
    
        function superPower() {
            console.log("Flying");
        }
    }
  • Pour plus d'informations, vous pouvez vous référer à JavaScript Scoping & Hoisting par Ben Cherry.

Comparison Operators & Equality

  • Utilisez === et !== plutôt que == et !=. eslint: eqeqeq

  • Les instructions conditionnelles telles que l'instruction if évaluent l'expression en utilisant la coercition avec la méthode abstraite ToBoolean et suivent toujours ces règles simples:

    • Objects évalué en true
    • Undefined évalué en false
    • Null évalué en false
    • Booleans évalué en valeur du boolean
    • Numbers évalué en false si +0, -0, or NaN, sinon true
    • Strings évalué en false si string vide '', sinon true
    if ([0] && []) {
        // true
        // an array (even an empty one) is an object, objects will evaluate to true
    }
  • Utilisez des raccourcis pour les booléens, mais des comparaisons explicites pour les chaînes et les nombres.

    // bad
    if (isValid === true) {
        // ...
    }
    
    // good
    if (isValid) {
        // ...
    }
    
    // bad
    if (name) {
        // ...
    }
    
    // good
    if (name !== "") {
        // ...
    }
    
    // bad
    if (collection.length) {
        // ...
    }
    
    // good
    if (collection.length > 0) {
        // ...
    }
  • Pour plus d'informations, regardez Truth Equality and JavaScript par Angus Croll.

  • Utilisez des accolades pour créer des blocs dans les clauses case et default qui contiennent des déclarations lexicales (par exemple, let, const, function et class). eslint: no-case-declarations.

    Les déclarations lexicales sont visibles dans tout le bloc switch mais ne sont initialisées que lorsqu'elles sont affectées, ce qui ne se produit que lorsque son case est atteint. Cela provoque des problèmes lorsque plusieurs clauses case tentent de définir la même chose.

    // bad
    switch (foo) {
        case 1:
            let x = 1;
            break;
        case 2:
            const y = 2;
            break;
        case 3:
            function f() {
                // ...
            }
            break;
        default:
            class C {}
    }
    
    // good
    switch (foo) {
        case 1: {
            let x = 1;
            break;
        }
        case 2: {
            const y = 2;
            break;
        }
        case 3: {
            function f() {
                // ...
            }
            break;
        }
        case 4:
            bar();
            break;
        default: {
            class C {}
        }
    }
  • Les ternaires ne doivent pas être imbriqués et sont généralement des expressions à une seule ligne. eslint: no-nested-ternary.

    // bad
    const foo = maybe1 > maybe2 ? "bar" : value1 > value2 ? "baz" : null;
    
    // better
    const maybeNull = value1 > value2 ? "baz" : null;
    
    const foo = maybe1 > maybe2 ? "bar" : maybeNull;
    
    // best
    const maybeNull = value1 > value2 ? "baz" : null;
    
    const foo = maybe1 > maybe2 ? "bar" : maybeNull;
  • Évitez les déclarations ternaires inutiles. eslint: no-unneeded-ternary.

    // bad
    const foo = a ? a : b;
    const bar = c ? true : false;
    const baz = c ? false : true;
    
    // good
    const foo = a || b;
    const bar = !!c;
    const baz = !c;

Blocks

  • Utilisez les accolades pour tous les blocks multilignes.

    // bad
    if (test) return false;
    
    // good
    if (test) return false;
    
    // good
    if (test) {
        return false;
    }
    
    // bad
    function foo() {
        return false;
    }
    
    // good
    function bar() {
        return false;
    }
  • Si vous utilisez des blocs multi-lignes avec if et else, placez else sur la même ligne que l'attache de fermeture de votre bloc if. eslint: brace-style

    // bad
    if (test) {
        thing1();
        thing2();
    } else {
        thing3();
    }
    
    // good
    if (test) {
        thing1();
        thing2();
    } else {
        thing3();
    }
  • Ne réassignez pas de variables dans les blocks conditionnels. eslint : no-cond-assign

    // bad
    let x;
    if ((x = 0)) {
        let b = 1;
    }
    
    // Practical example that is similar to an error
    function setHeight(someNode) {
        "use strict";
        do {
            someNode.height = "100px";
        } while ((someNode = someNode.parentNode));
    }

Commentaires

  • Utilisez /** ... */ pour les commentaires multilignes.

    // bad
    // make() returns a new element
    // based on the passed in tag name
    //
    // @param {String} tag
    // @return {Element} element
    function make(tag) {
        // ...
    
        return element;
    }
    
    // good
    /**
     * make() returns a new element
     * based on the passed-in tag name
     */
    function make(tag) {
        // ...
    
        return element;
    }
  • Utilisez // pour les commentaires d'une seule ligne. Placez les commentaires d'une ligne sur une nouvelle ligne au-dessus du sujet du commentaire. Mettez une ligne vide avant le commentaire sur la première ligne d'un bloc.

    // bad
    const active = true; // is current tab
    
    // good
    // is current tab
    const active = true;
    
    // bad
    function getType() {
        console.log("fetching type...");
        // set the default type to 'no type'
        const type = this.type || "no type";
    
        return type;
    }
    
    // good
    function getType() {
        console.log("fetching type...");
    
        // set the default type to 'no type'
        const type = this.type || "no type";
    
        return type;
    }
    
    // also good
    function getType() {
        // set the default type to 'no type'
        const type = this.type || "no type";
    
        return type;
    }
  • Commencez tous les commentaires avec un espace pour faciliter la lecture. eslint: spaced-comment

    // bad
    //is current tab
    const active = true;
    
    // good
    // is current tab
    const active = true;
    
    // bad
    /**
     *make() returns a new element
     *based on the passed-in tag name
     */
    function make(tag) {
        // ...
    
        return element;
    }
    
    // good
    /**
     * make() returns a new element
     * based on the passed-in tag name
     */
    function make(tag) {
        // ...
    
        return element;
    }
  • Préfixer vos commentaires avec FIXME ou TODO peut aider d'autres développeurs à comprendre rapidement si vous signalez un problème qui doit être revu, ou si vous proposez une solution au problème qui doit être mis en œuvre. Ceux-ci sont différents des commentaires réguliers parce qu'ils sont susceptibles d'indiquer une action à effectuer. Les actions sont FIXME: - besoin de comprendre cela ou TODO: - besoin d'implémenter.

  • Utilisez // FIXME: pour noter un problème

    class Calculator extends Abacus {
        constructor() {
            super();
    
            // FIXME: shouldn't use a global here
            total = 0;
        }
    }
  • Utilisez // TODO: pour indiquer une action à faire ou pour donner une solution à un problème.

    class Calculator extends Abacus {
        constructor() {
            super();
    
            // TODO: total should be configurable by an options param
            this.total = 0;
        }
    }

Whitespaces

  • Utilisez l'indentation légère (caractère espace) composé de 4 espaces. eslint: indent

    // bad
    function foo() {
    ∙∙let name;
    }
    
    // bad
    function bar() {
    ∙let name;
    }
    
    // good
    function baz() {
    ∙∙∙∙let name;
    }
  • Placez 1 espace avant l'accolade de tête. eslint: space-before-blocks

    // bad
    function test() {
        console.log("test");
    }
    
    // good
    function test() {
        console.log("test");
    }
    
    // bad
    dog.set("attr", {
        age: "1 year",
        breed: "Bernese Mountain Dog",
    });
    
    // good
    dog.set("attr", {
        age: "1 year",
        breed: "Bernese Mountain Dog",
    });
  • Placez 1 espace avant la parenthèse ouvrante dans les instructions de contrôle (if, while, etc.). Ne placez aucun espace entre la liste des arguments et le nom de la fonction dans les appels de fonction et les déclarations. eslint: keyword-spacing

    // bad
    if (isJedi) {
        fight();
    }
    
    // good
    if (isJedi) {
        fight();
    }
    
    // bad
    function fight() {
        console.log("Swooosh!");
    }
    
    // good
    function fight() {
        console.log("Swooosh!");
    }
  • Séparer les opérateurs avec des espaces. eslint: space-infix-ops

    // bad
    const x = y + 5;
    
    // good
    const x = y + 5;
  • Terminez vos fichiers par une ligne vide. eslint: eol-last

    // bad
    import { es6 } from "./AirbnbStyleGuide";
    // ...
    export default es6;
    // bad
    import { es6 } from './AirbnbStyleGuide';
      // ...
    export default es6;
    
    // good
    import { es6 } from './AirbnbStyleGuide';
      // ...
    export default es6;
  • Utilisez l'indentation lors de la création de longues chaînes de méthodes (plus de 2 chaînes de méthodes). Utilisez un point de tête, qui souligne que la ligne est un appel de méthode, pas une nouvelle instruction. eslint: newline-per-chained-call no-whitespace-before-property

    // bad
    $("#items").find(".selected").highlight().end().find(".open").updateCount();
    
    // bad
    $("#items").find(".selected").highlight().end().find(".open").updateCount();
    
    // good
    $("#items").find(".selected").highlight().end().find(".open").updateCount();
    
    // bad
    const leds = stage
        .selectAll(".led")
        .data(data)
        .enter()
        .append("svg:svg")
        .classed("led", true)
        .attr("width", (radius + margin) * 2)
        .append("svg:g")
        .attr("transform", `translate(${radius + margin},${radius + margin})`)
        .call(tron.led);
    
    // good
    const leds = stage
        .selectAll(".led")
        .data(data)
        .enter()
        .append("svg:svg")
        .classed("led", true)
        .attr("width", (radius + margin) * 2)
        .append("svg:g")
        .attr("transform", `translate(${radius + margin},${radius + margin})`)
        .call(tron.led);
    
    // good
    const leds = stage.selectAll(".led").data(data);
  • Laissez une ligne blanche après un block et le statement qui suit.

    // bad
    if (foo) {
        return bar;
    }
    return baz;
    
    // good
    if (foo) {
        return bar;
    }
    
    return baz;
    
    // bad
    const obj = {
        foo() {},
        bar() {},
    };
    return obj;
    
    // good
    const obj = {
        foo() {},
        bar() {},
    };
    
    return obj;
    
    // bad
    const arr = [function foo() {}, function bar() {}];
    return arr;
    
    // good
    const arr = [function foo() {}, function bar() {}];
    
    return arr;
  • Ne commencez et/ou ne finissez pas vos blocks par une ligne vide. eslint: padded-blocks

    // bad
    function bar() {
        console.log(foo);
    }
    
    // also bad
    if (baz) {
        console.log(qux);
    } else {
        console.log(foo);
    }
    
    // good
    function bar() {
        console.log(foo);
    }
    
    // good
    if (baz) {
        console.log(qux);
    } else {
        console.log(foo);
    }
  • Ne mettez pas d'espace dans les parenthèses. eslint: space-in-parens

    // bad
    function bar(foo) {
        return foo;
    }
    
    // good
    function bar(foo) {
        return foo;
    }
    
    // bad
    if (foo) {
        console.log(foo);
    }
    
    // good
    if (foo) {
        console.log(foo);
    }
  • Ne pas mettre d'espaces entre crochets. eslint: array-bracket-spacing

    // bad
    const foo = [1, 2, 3];
    console.log(foo[0]);
    
    // good
    const foo = [1, 2, 3];
    console.log(foo[0]);
  • Ajoutez des espaces dans des accolades. eslint: object-curly-spacing

    // bad
    const foo = { clark: "kent" };
    
    // good
    const foo = { clark: "kent" };
  • Évitez d'avoir des lignes de code qui sont plus long que 125 caractères (y compris les espaces). Note: les chaînes longues sont exemptées de cette règle et ne doivent pas être rompues. eslint: max-len

    Cela garantit la lisibilité et la maintenabilité.

    // bad
    const foo =
        jsonData &&
        jsonData.foo &&
        jsonData.foo.bar &&
        jsonData.foo.bar.baz &&
        jsonData.foo.bar.baz.quux &&
        jsonData.foo.bar.baz.quux.xyzzy;
    
    // bad
    $.ajax({
        method: "POST",
        url: "https://airbnb.com/",
        data: { name: "John" },
    })
        .done(() => console.log("Congratulations!"))
        .fail(() => console.log("You have failed this city."));
    
    // good
    const foo =
        jsonData &&
        jsonData.foo &&
        jsonData.foo.bar &&
        jsonData.foo.bar.baz &&
        jsonData.foo.bar.baz.quux &&
        jsonData.foo.bar.baz.quux.xyzzy;
    
    // good
    $.ajax({
        method: "POST",
        url: "https://airbnb.com/",
        data: { name: "John" },
    })
        .done(() => console.log("Congratulations!"))
        .fail(() => console.log("You have failed this city."));
  • Pour les objets définits sur plusieurs lignes, aligner les clés/valeurs. eslint : key-spacing

    // bad
    const obj = {
        firstname: "Joe",
        lastname: "Black",
        age: 12,
    };
    
    // good
    const obj = {
        firstname: "Joe",
        lastname: "Black",
        age: 12,
    };
  • Ne mettez jamais d'espace lors de l'utilisation du spread/rest operator (...). eslint : rest-spread-spacing

    // bad
    fn(... args)
    [... arr, 4, 5, 6]
    let [a, b, ... arr] = [1, 2, 3, 4, 5];
    function fn(... args) { console.log(args); }
    let { x, y, ... z } = { x: 1, y: 2, a: 3, b: 4 };
    let n = { x, y, ... z };
    
    // good
    fn(...args)
    [...arr, 4, 5, 6]
    let [a, b, ...arr] = [1, 2, 3, 4, 5];
    function fn(...args) { console.log(args); }
    let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
    let n = { x, y, ...z };

Virgules

  • Virgules en début de ligne ? NOPE. eslint: comma-style

    // bad
    const story = [once, upon, aTime];
    
    // good
    const story = [once, upon, aTime];
    
    // bad
    const hero = {
        firstName: "Ada",
        lastName: "Lovelace",
        birthYear: 1815,
        superPower: "computers",
    };
    
    // good
    const hero = {
        firstName: "Ada",
        lastName: "Lovelace",
        birthYear: 1815,
        superPower: "computers",
    };
  • Mettre une virgule en fin d'objet/array. eslint: comma-dangle

    Cela conduit à des différences de git plus simples. En outre, les transpilers comme Babel supprimeront la virgule de fin de traînée dans le code transpillé qui signifie que vous n'avez pas à vous soucier du [problème de dernière virgule] (https://github.com/airbnb/javascript/blob/es5-deprecated/es5/README.md#commas) sur les navigateurs.

    // bad - git diff without trailing comma
    const hero = {
         firstName: 'Florence',
    -    lastName: 'Nightingale'
    +    lastName: 'Nightingale',
    +    inventorOf: ['coxcomb chart', 'modern nursing']
    };
    
    // good - git diff with trailing comma
    const hero = {
         firstName: 'Florence',
         lastName: 'Nightingale',
    +    inventorOf: ['coxcomb chart', 'modern nursing'],
    };
    // bad
    const hero = {
        firstName: "Dana",
        lastName: "Scully",
    };
    
    const heroes = ["Batman", "Superman"];
    
    // good
    const hero = {
        firstName: "Dana",
        lastName: "Scully",
    };
    
    const heroes = ["Batman", "Superman"];
    
    // bad
    function createHero(firstName, lastName, inventorOf) {
        // does nothing
    }
    
    // good
    function createHero(firstName, lastName, inventorOf) {
        // does nothing
    }
    
    // good (note that a comma must not appear after a "rest" element)
    function createHero(firstName, lastName, inventorOf, ...heroArgs) {
        // does nothing
    }
    
    // bad
    createHero(firstName, lastName, inventorOf);
    
    // good
    createHero(firstName, lastName, inventorOf);
    
    // good (note that a comma must not appear after a "rest" element)
    createHero(firstName, lastName, inventorOf, ...heroArgs);

Points-virgules

  • Obligatoire en fin d'un statement (si elles existent c'est pour une bonne raison). eslint: semi

    // bad
    (function () {
        const name = "Skywalker";
        return name;
    })()(
        // good
        (function () {
            const name = "Skywalker";
            return name;
        })()
    );
    
    // good, but legacy (guards against the function becoming an argument when two files with IIFEs are concatenated)
    (() => {
        const name = "Skywalker";
        return name;
    })();

Type Casting & Coercion

  • Effectuer la coercition de type au début de la déclaration.

  • Strings:

    // => this.reviewScore = 9;
    
    // bad
    const totalScore = this.reviewScore + ""; // invokes this.reviewScore.valueOf()
    
    // bad
    const totalScore = this.reviewScore.toString(); // isn't guaranteed to return a string
    
    // good
    const totalScore = String(this.reviewScore);
  • Nombres. Selon les cas, utilisez l'opérateur + ou bien parseInt en précisant obligatoirement sa base de conversion. Privilégiez ce dernier le plus possible. eslint: radix

    const inputValue = "4";
    
    // bad
    const val = new Number(inputValue);
    
    // good
    const val = +inputValue;
    
    // bad
    const val = inputValue >> 0;
    
    // bad
    const val = parseInt(inputValue);
    
    // good
    const val = Number(inputValue);
    
    // good
    const val = parseInt(inputValue, 10);
  • Si pour une raison ou pour une autre, vous faites un traitement contenant un parseInt et que celui-ci vous ralenti fortement votre traitement, dans ce cas vous pouvez utiliser le décallage de bits. Mais uniquement pour des raisons de performance. Dans ce cas, laissez un commentaire expliquant pourquoi vous faites ça.

    // good
    /**
     * 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;
  • Note : Faites très attention lors de l'utilisation des décallages de bits. Les nombres sont représentés sur 64-bit. Le décallage de bits retourne toujours des nombres représentés sur 32 bits (source). Ceci peut entraîner des conversions erronées et non prévues pour les nombres plus larges que 32 bits. Discussion. Le plus grand nombre signé sur 32 bits est de 2147483647 :

    2147483647 >> 0; // => 2147483647
    2147483648 >> 0; // => -2147483648
    2147483649 >> 0; // => -2147483647
  • Booléens :

    const age = 0;
    
    // bad
    const hasAge = new Boolean(age);
    
    // good
    const hasAge = Boolean(age);
    
    // best
    const hasAge = !!age;

Convention de nommage

  • Évitez les noms composés d'une seule lettre. Soyez descriptif avec votre nom. eslint: id-length

    // bad
    function q() {
        // ...
    }
    
    // good
    function query() {
        // ...
    }
  • Utilisez le camelCase quand vous nommez des objets, functions et instances. eslint: camelcase

    // bad
    const OBJEcttsssss = {};
    const this_is_my_object = {};
    function c() {}
    
    // good
    const thisIsMyObject = {};
    function thisIsMyFunction() {}
  • Utilisez le PascalCase uniquement pour nommer vos constructeurs et classes. eslint: new-cap

    // bad
    function user(options) {
        this.name = options.name;
    }
    
    const bad = new user({
        name: "nope",
    });
    
    // good
    class User {
        constructor(options) {
            this.name = options.name;
        }
    }
    
    const good = new User({
        name: "yup",
    });
  • N'utilisez pas les traits d'union et les underscore. eslint: no-underscore-dangle

    JavaScript n'a pas le concept de choses privées en termes de propriétés ou de méthodes. Bien qu'un underscore en début de nom est une convention commune pour signifier "privé", en fait, ces propriétés sont pleinement publiques, et comme tel, font partie de votre API public. Cette convention pourrait conduire les développeurs à penser à tort qu'une modification ne sera pas considérée comme rupture, ou que des tests ne sont pas nécessaires. Tl; dr: si vous voulez que quelque chose soit «privé», il ne doit pas être présent.

    // bad
    this.__firstName__ = "Panda";
    this.firstName_ = "Panda";
    this._firstName = "Panda";
    
    // good
    this.firstName = "Panda";
  • Ne sauvegardez pas la référence de this. Utilisez les fonctions fléchées ou bien Function#bind.

    // bad
    function foo() {
        const self = this;
        return function () {
            console.log(self);
        };
    }
    
    // bad
    function foo() {
        const that = this;
        return function () {
            console.log(that);
        };
    }
    
    // good
    function foo() {
        return () => {
            console.log(this);
        };
    }
  • Le nom du fichier doit correspondre au nom de la variable pour son export par défaut.

    // file 1 contents
    class CheckBox {
      // ...
    }
    export default CheckBox;
    
    // file 2 contents
    export default function fortyTwo() { return 42; }
    
    // file 3 contents
    export default function insideDirectory() {}
    
    // in some other file
    // bad
    import CheckBox from './checkBox'; // PascalCase import/export, camelCase filename
    import FortyTwo from './FortyTwo'; // PascalCase import/filename, camelCase export
    import InsideDirectory from './InsideDirectory'; // PascalCase import/filename, camelCase export
    
    // bad
    import CheckBox from './check_box'; // PascalCase import/export, snake_case filename
    import forty_two from './forty_two'; // snake_case import/filename, camelCase export
    import inside_directory from './inside_directory'; // snake_case import, camelCase export
    import index from './inside_directory/index'; // requiring the index file explicitly
    import insideDirectory from './insideDirectory/index'; // requiring the index file explicitly
    
    // good
    import CheckBox from './CheckBox'; // PascalCase export/import/filename
    import fortyTwo from './fortyTwo'; // camelCase export/import/filename
    import insideDirectory from './insideDirectory'; // camelCase export/import/directory name/implicit "index"
    // ^ supports both insideDirectory.js and insideDirectory/index.js
  • Utilisez le camelCase quand le export default est pour une fonction. Votre fichier nom de fichier doit être identique à votre fonction

    function makeStyleGuide() {
        // ...
    }
    
    export default makeStyleGuide;
  • Utilisez le PascalCase quand le export default est pour un constructor / classes / singleton / constante

    const AirbnbStyleGuide = {
        es6: {},
    };
    
    export default AirbnbStyleGuide;
  • Les acronymes et les initialismes doivent toujours être en majuscules ou entièrement en minuscules.

    // bad
    import SmsContainer from "./containers/SmsContainer";
    
    // bad
    const HttpRequests = [
        // ...
    ];
    
    // good
    import SMSContainer from "./containers/SMSContainer";
    
    // good
    const HTTPRequests = [
        // ...
    ];
    
    // best
    import TextMessageContainer from "./containers/TextMessageContainer";
    
    // best
    const Requests = [
        // ...
    ];

Accessors

  • Les fonctions d'accesseur pour les propriétés ne sont pas requises.

  • N'utilisez pas les getters / setters JavaScript car ils provoquent des effets secondaires inattendus et sont plus difficiles à tester, à maintenir et à raisonner. Au lieu de cela, si vous faites des fonctions d'accesseur, utilisez getVal() et setVal('bonjour').

    // bad
    class Dragon {
        get age() {
            // ...
        }
        set age(value) {
            // ...
        }
    }
    
    // good
    class Dragon {
        getAge() {
            // ...
        }
        setAge(value) {
            // ...
        }
    }
  • Si la propriété est un booléen, utilisez isVal() ou hasVal()

    // bad
    if (!dragon.dead()) {
        return false;
    }
    
    // good
    if (!dragon.isDead()) {
        return false;
    }
  • Vous pouvez très bien utiliser les fonctions get() et set() mais soyez cohérents.

    class Jedi {
        constructor(options = {}) {
            const lightsaber = options.lightsaber || "blue";
            this.set("lightsaber", lightsaber);
        }
        set(key, val) {
            this[key] = val;
        }
        get(key) {
            return this[key];
        }
    }

Events

  • Quand vous attachez des paramètres à des événements (événements VueJS, ReactJS ou NodeJS), passez par un objet plutôt que par la valeur brute. Cela permet d'ajouter plus facilement d'autres paramètres à cette fonction sans devoir tout reprendre. Par exemple, au lieux de faire :

    this.emit("listingUpdated", listing.id);
    
    // ...
    
    this.on("listingUpdated", (listingId) => {
        // do something with listingId
    });

    préférez :

    this.emit("listingUpdated", {
        listingId: listing.id,
    });
    
    // ...
    
    this.on("listingUpdated", (data) => {
        // do something with listingId
    });

jQuery

  • Ne plus jamais utiliser jQuery dans vos projets ni de library externes l'utilisant. Pour le front, les nouveaux frameworks font le job sans nécessairement inclure jQuery. De plus, lors de la compilation, vous risquez d'avoir des library qui ont jQuery dans différentes versions et cela peut entraîner des erreurs d'exécution car la compilation retournera différentes occurences de jQuery.

VueJS

  • Utilisation des règles de plugin:vue/recommended : Voir les règles mais avec des changements minimes :

  • Surcharge de la rules vue/html-indent. L'espacement dans le tag template est de 4 espaces :

    // bad
    <template>
        <div class="item">
            <span>Contenu du span</span>
        </div>
    </template>
    
    // good
    <template>
        <div class="item">
            <span>Contenu du span</span>
        </div>
    </template>
  • Surcharge de la rule vue/component-name-in-template-casing. Les composants dans le HTML appelés autrement qu'en kebabCase sont retournés en erreur.

    <template>
        <!-- ✓ GOOD -->
        <the-component />
    
        <!-- ✗ BAD -->
        <TheComponent />
        <theComponent />
        <Thecomponent />
        <The-component />
    </template>
  • Surcharge de la rule vue/html-closing-bracket-newline. Les sauts de ligne avant la fermeture des tags n'est pas autorisée.

    <template>
        <!-- ✓ GOOD -->
        <div id="foo" class="bar">
        <div
            id="foo"
            class="bar">
    
        <!-- ✗ BAD -->
        <div id="foo" class="bar"
        >
        <div
            id="foo"
            class="bar"
        >
    </template>

Performance

Resources

Learning ES6

Read This

Tools

Other Style Guides

Other Styles

Further Reading

Books

Blogs

Podcasts