eslint-config-throrinstudio v2.0.0
Throrinstudio Javascript Styleguide
Table of Content
- Table of Content
- Installation
- Utilisation
- Types
- References
- Objects
- Arrays
- Destructuring
- Strings
- Functions
- Arrow Functions
- Classes et Constructeurs
- Modules (uniquement pour projets Front pour le moment)
- Iterators et Generators
- Promesses
- Properties
- variables
- Hoisting
- Comparison Operators & Equality
- Blocks
- Commentaires
- Whitespaces
- Virgules
- Points-virgules
- Type Casting & Coercion
- Convention de nommage
- Accessors
- Events
- jQuery
- VueJS
- Performance
- Resources
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 pasvar
. 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 devar
. eslint:no-var
let
est "block-scoped" alors quevar
est "function-scopped"// bad var count = 1; if (true) { count += 1; } // good, use the let. let count = 1; if (true) { count += 1; }
Important :
let
etconst
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-evalNe 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'objetarguments
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
avecapply
.// 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
, etbreak
. 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 unbind(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 unreturn
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 manipulerprototype
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éritagesIl 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
oufor-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 , EtObject.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 pourfunction
,function*
est une construction unique, différente defunction
.// 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. eslintno-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 voslet
.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
etconst
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 deconst
etlet
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 abstraiteToBoolean
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
etdefault
qui contiennent des déclarations lexicales (par exemple,let
,const
,function
etclass
). 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 soncase
est atteint. Cela provoque des problèmes lorsque plusieurs clausescase
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
etelse
, placezelse
sur la même ligne que l'attache de fermeture de votre blocif
. 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
ouTODO
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 sontFIXME: - besoin de comprendre cela
ouTODO: - besoin d'implémenter
.Utilisez
// FIXME:
pour noter un problèmeclass 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 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 bienparseInt
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 n