Featured image of post Guide de style JavaScript Airbnb

Guide de style JavaScript Airbnb

Guide de style JavaScript Airbnb

Photo by Pankaj Patel on Unsplash

https://github.com/jigsawye/javascript

Guide de style JavaScript Airbnb()

Une approche raisonnable pour le JavaScript.

Downloads Gitter

Autres guides de style

Traduit de Airbnb JavaScript Style Guide.

Types (Types)

  • 1.1 Primitifs (Primitives) : Vous accédez aux types primitifs directement.
  • string
  • number
  • boolean
  • null
  • undefined
const foo = 1;
let bar = foo;

bar = 9;

console.log(foo, bar); // => 1, 9
  • 1.2 Complexes (Complex) : Vous accédez aux types complexes par référence (by reference).
  • object
  • array
  • function
const foo = [1, 2];
const bar = foo;

bar[0] = 9;

console.log(foo[0], bar[0]); // => 9, 9

Références (References)

Pourquoi ? Cela garantit que vous ne pouvez pas réassigner vos références, ce qui peut entraîner des bugs et un code difficile à comprendre.

// bad
var a = 1;
var b = 2;

// good
const a = 1;
const b = 2;
  • 2.2 Si vous devez réassigner des références, utilisez let au lieu de var. eslint : no-var jscs : disallowVar

Pourquoi ? let a une portée de bloc (block-scoped), tandis que var a une portée de fonction (function-scoped).

// bad
var count = 1;
if (true) {
    count += 1;
}

// good, use the let.
let count = 1;
if (true) {
    count += 1;
}
  • 2.3 Notez que let et const ont tous deux une portée de bloc.
// const et let n'existent qu'à l'intérieur des blocs où ils sont définis.
{
    let a = 1;
    const b = 1;
}
console.log(a); // ReferenceError
console.log(b); // ReferenceError

Objets (Objects)

  • 3.1 Utilisez la syntaxe littérale pour la création d’objets. eslint rules : no-new-object.
// bad
const item = new Object();

// good
const item = {};
// bad
const superman = {
    default: { clark: 'kent' },
    private: true,
};

// good
const superman = {
    defaults: { clark: 'kent' },
    hidden: true,
};
// bad
const superman = {
    class: 'alien',
};

// bad
const superman = {
    klass: 'alien',
};

// good
const superman = {
    type: 'alien',
};

  • 3.4 Utilisez des noms de propriétés calculés (computed property names) lors de la création d’objets avec des noms de propriétés dynamiques.

Pourquoi ? Ils vous permettent de définir toutes les propriétés de l’objet en un seul endroit.


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,
};

// bad
const atom = {
    value: 1,

    addValue: function (value) {
    return atom.value + value;
    },
};

// good
const atom = {
    value: 1,

    addValue(value) {
    return atom.value + value;
    },
};

Pourquoi ? C’est plus court et plus descriptif.

const lukeSkywalker = 'Luke Skywalker';

// bad
const obj = {
    lukeSkywalker: lukeSkywalker,
};

// good
const obj = {
    lukeSkywalker,
};
  • 3.7 Groupez vos notations abrégées au début de votre déclaration d’objet.

Pourquoi ? Il est plus facile de voir quelles propriétés utilisent la notation abrégée.

const anakinSkywalker = 'Anakin Skywalker';
const lukeSkywalker = 'Luke Skywalker';

// bad
const obj = {
    episodeOne: 1,
    twoJediWalkIntoACantina: 2,
    lukeSkywalker,
    episodeThree: 3,
    mayTheFourth: 4,
    anakinSkywalker,
};

// good
const obj = {
    lukeSkywalker,
    anakinSkywalker,
    episodeOne: 1,
    twoJediWalkIntoACantina: 2,
    episodeThree: 3,
    mayTheFourth: 4,
};

Pourquoi ? En général, nous considérons que c’est subjectivement plus facile à lire. Cela améliore la coloration syntaxique et est également plus facile à optimiser par de nombreux moteurs JS.

// bad
const bad = {
    'foo': 3,
    'bar': 4,
    'data-blah': 5,
};

// good
const good = {
    foo: 3,
    bar: 4,
    'data-blah': 5,
};

Tableaux (Arrays)

// bad
const items = new Array();

// good
const items = [];
  • 4.2 Utilisez Array#push au lieu d’une affectation directe pour ajouter des éléments à un tableau.
const someStack = [];

// bad
someStack[someStack.length] = 'abracadabra';

// good
someStack.push('abracadabra');

  • 4.3 Utilisez les spreads de tableau ... pour copier des tableaux.
// bad
const len = items.length;
const itemsCopy = [];
let i;

for (i = 0; i < len; i++) {
    itemsCopy[i] = items[i];
}

// good
const itemsCopy = [...items];
  • 4.4 Pour convertir un objet de type array (array-like object) en tableau, utilisez Array#from.
const foo = document.querySelectorAll('.foo');
const nodes = Array.from(foo);
  • 4.5 Utilisez des instructions de retour dans les callbacks de méthodes de tableau. Il est acceptable d’omettre le retour si le corps de la fonction consiste en une seule instruction suivant 8.2. 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] = memo.concat(item);
});

// 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;
});

Déstructuration (Destructuring)

  • 5.1 Utilisez la déstructuration d’objet lorsque vous accédez et utilisez plusieurs propriétés d’un objet. jscs : requireObjectDestructuring

Pourquoi ? La déstructuration vous évite de créer des références temporaires 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}`;
}
const arr = [1, 2, 3, 4];

// bad
const first = arr[0];
const second = arr[1];

// good
const [first, second] = arr;
  • 5.3 Utilisez la déstructuration d’objet pour plusieurs valeurs de retour, pas la déstructuration de tableau.

Pourquoi ? Vous pouvez ajouter de nouvelles propriétés ou changer l’ordre des éléments sans casser les sites d’appel (call sites).

// 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, right } = processInput(input);

Chaînes de caractères (Strings)

// bad
const name = "Capt. Janeway";

// good
const name = 'Capt. Janeway';
  • 6.2 Les chaînes de caractères qui font dépasser la ligne de 100 caractères ne doivent pas être écrites sur plusieurs lignes en utilisant la concaténation de chaînes.
  • 6.3 Note : Si utilisé excessivement, les longues chaînes avec concaténation peuvent impacter les performances. jsPerf & Discussion.
// 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.';

Pourquoi ? Les template strings vous donnent une syntaxe lisible et concise avec des sauts de ligne et des fonctionnalités d’interpolation de chaînes.

// 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}?`;
}
  • 6.5 N’utilisez jamais eval() sur une chaîne de caractères, cela ouvre trop de vulnérabilités.

Fonctions (Functions)

  • 7.1 Utilisez des déclarations de fonction (function declarations) au lieu d’expressions de fonction (function expressions). jscs : requireFunctionDeclarations

Pourquoi ? Les déclarations de fonction sont nommées, elles sont donc plus faciles à identifier dans les stack traces. De plus, les déclarations de fonction sont hissées (hoisted), contrairement aux expressions de fonction. Cette règle permet aux Fonctions Fléchées de remplacer complètement les expressions de fonction.

// bad
const foo = function () {
};

// good
function foo() {
}

Pourquoi ? Une IIFE est une unité unique - envelopper la fonction et son appel entre parenthèses rend cela clair. Notez que dans un monde avec des modules, vous n’avez presque pas besoin d’IIFE.

// immediately-invoked function expression (IIFE)
(function () {
    console.log('Welcome to the Internet. Please follow me.');
}());
  • 7.3 Ne déclarez jamais une fonction dans un bloc non-fonctionnel (if, while, etc). Assignez la fonction à une variable à la place. Les navigateurs vous permettront de le faire, mais ils l’interprètent tous différemment. eslint : no-loop-func

  • 7.4 Note : ECMA-262 définit un bloc comme une liste d’instructions. Une déclaration de fonction n’est pas une instruction. Lire la note d’ECMA-262 sur ce problème.

// bad
if (currentUser) {
    function test() {
    console.log('Nope.');
    }
}

// good
let test;
if (currentUser) {
    test = () => {
    console.log('Yup.');
    };
}
  • 7.5 Ne nommez jamais un paramètre arguments. Cela prendra le pas sur l’objet arguments qui est donné à chaque portée de fonction.
// bad
function nope(name, options, arguments) {
    // ...stuff...
}

// good
function yup(name, options, args) {
    // ...stuff...
}

Pourquoi ? ... rend explicite les arguments que vous souhaitez récupérer. De plus, les arguments rest sont un véritable Tableau, et pas seulement de type Array comme arguments.

// bad
function concatenateAll() {
    const args = Array.prototype.slice.call(arguments);
    return args.join('');
}

// good
function concatenateAll(...args) {
    return args.join('');
}

  • 7.7 Utilisez la syntaxe des paramètres par défaut au lieu de modifier les arguments de la fonction.
// really bad
function handleThings(opts) {
    // No! We shouldn't mutate function arguments.
    // Double bad: if opts is false it will be set to an object which may
    // be what you want but it can cause subtle bugs.
    opts = opts || {};
    // ...
}

// still bad
function handleThings(opts) {
    if (opts === void 0) {
    opts = {};
    }
    // ...
}

// good
function handleThings(opts = {}) {
    // ...
}
  • 7.8 Évitez les effets de bord avec les paramètres par défaut.

Pourquoi ? Ils sont déroutants à comprendre.

var b = 1;
// bad
function count(a = b++) {
    console.log(a);
}
count();  // 1
count();  // 2
count(3); // 3
count();  // 3
  • 7.9 Mettez toujours les paramètres par défaut en dernier.
// bad
function handleThings(opts = {}, name) {
    // ...
}

// good
function handleThings(name, opts = {}) {
    // ...
}
  • 7.10 N’utilisez jamais le constructeur Function pour créer une nouvelle fonction.

Pourquoi ? Créer une fonction de cette manière évalue une chaîne de caractères de la même manière que eval(), ce qui ouvre des vulnérabilités.

// bad
var add = new Function('a', 'b', 'return a + b');

// still bad
var subtract = Function('a', 'b', 'return a - b');
  • 7.11 Espacement dans une signature de fonction.

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

// bad
const f = function(){};
const g = function (){};
const h = function() {};

// good
const x = function () {};
const y = function a() {};

Pourquoi ? La manipulation d’objets passés en tant que paramètres peut provoquer des effets de bord indésirables chez l’appelant d’origine.

// bad
function f1(obj) {
    obj.key = 1;
};

// good
function f2(obj) {
    const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1;
};

Pourquoi ? La réaffectation de paramètres peut entraîner un comportement inattendu, en particulier lors de l’accès à l’objet arguments. Cela peut également causer des problèmes d’optimisation, en particulier dans V8.

```javascript
// 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) {
}
```

Fonctions Fléchées (Arrow Functions)

Pourquoi ? Cela crée une version de la fonction qui s’exécute dans le contexte de this, ce qui est généralement ce que vous voulez, et c’est une syntaxe plus concise.

Pourquoi pas ? Si vous avez une fonction assez complexe, vous pouvez déplacer cette logique dans sa propre déclaration de fonction nommée.

// 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;
});

Pourquoi ? Sucre syntaxique (Syntactic sugar). C’est plus lisible lorsque plusieurs fonctions sont enchaînées ensemble.

Pourquoi pas ? Si vous prévoyez de retourner un objet.

// 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}.`;
});
  • 8.3 Si l’expression s’étend sur plusieurs lignes, enveloppez-la entre parenthèses pour une meilleure lisibilité.

Pourquoi ? Cela montre clairement où la fonction commence et se termine.

// bad
[1, 2, 3].map(number => 'As time went by, the string containing the ' +
    `${number} became much longer. So we needed to break it over multiple ` +
    'lines.'
);

// good
[1, 2, 3].map(number => (
    `As time went by, the string containing the ${number} became much ` +
    'longer. So we needed to break it over multiple lines.'
));

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’ve broken it ` +
    'over multiple lines!'
));

// 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;
});
  • 8.5 É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 => { return item.height > 256 ? item.largeSize : item.smallSize; }

Constructeurs (Constructors)

  • 9.1 Utilisez toujours class. Évitez de manipuler prototype directement.

Pourquoi ? 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;
    }
}
  • 9.2 Utilisez extends pour l’héritage.

Pourquoi ? C’est un moyen intégré d’hériter de la fonctionnalité du 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];
    }
}
  • 9.3 Les méthodes peuvent retourner this pour aider au chaînage de méthodes (method chaining).
// 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);
  • 9.4 Il est acceptable d’écrire une méthode toString() personnalisée, assurez-vous simplement qu’elle fonctionne correctement et ne provoque pas d’effets de bord.
class Jedi {
    constructor(options = {}) {
    this.name = options.name || 'no name';
    }

    getName() {
    return this.name;
    }

    toString() {
    return `Jedi - ${this.getName()}`;
    }
}
  • 9.5 Les classes ont un constructeur par défaut s’il n’est pas spécifié. Un constructeur vide ou un constructeur qui ne fait que déléguer à une classe parente est inutile. 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';
    }
}

Modules (Modules)

  • 10.1 Utilisez toujours des modules (import/export) plutôt qu’un système de modules non standard. Vous pouvez toujours transpiler vers votre système de modules préféré.

Pourquoi ? Les modules sont l’avenir, commençons à utiliser l’avenir maintenant.

// 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;
  • 10.2 N’utilisez pas d’importations avec des caractères génériques (wildcard imports).

Pourquoi ? Cela garantit que vous avez un seul export par défaut.

// bad
import * as AirbnbStyleGuide from './AirbnbStyleGuide';

// good
import AirbnbStyleGuide from './AirbnbStyleGuide';
  • 10.3 Et n’exportez pas directement depuis un import.

Pourquoi ? Bien que l’écriture en une seule ligne soit concise, avoir une manière claire d’importer et une manière claire 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;

Itérateurs et Générateurs (Iterators and Generators)

  • 11.1 N’utilisez pas d’itérateurs. Préférez les fonctions d’ordre supérieur de JavaScript comme map() et reduce() au lieu de boucles comme for-of. eslint : no-iterator

Pourquoi ? Cela impose notre règle d’immutabilité. Traiter avec des fonctions pures qui retournent des valeurs est plus facile à raisonner que les effets de bord.

eslint rules : no-iterator.

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;
  • 11.2 N’utilisez pas de générateurs pour le moment.

Pourquoi ? Ils ne se transpilent pas encore bien en ES5.

Propriétés (Properties)

const luke = {
    jedi: true,
    age: 28,
};

// bad
const isJedi = luke['jedi'];

// good
const isJedi = luke.jedi;
  • 12.2 Utilisez la notation par crochets [] lors de l’accès aux propriétés avec une variable.
const luke = {
    jedi: true,
    age: 28,
};

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

const isJedi = getProp('jedi');

Variables (Variables)

  • 13.1 Utilisez toujours const ou let pour déclarer des variables. Ne pas le faire entraînera des variables globales. Nous voulons éviter de polluer l’espace de noms global. Le Capitaine Planète nous a mis en garde contre cela.
// bad
superPower = new SuperPower();

// good
const superPower = new SuperPower();

Pourquoi ? Il est plus facile d’ajouter de nouvelles déclarations de variables de cette manière, et vous n’avez jamais à vous soucier d’échanger un ; contre une , ou d’introduire des différences de ponctuation uniquement.

// bad
const items = getItems(),
    goSportsTeam = true,
    dragonball = 'z';

// bad
// (compare to above, notice the error)
const items = getItems(),
    goSportsTeam = true;
    dragonball = 'z';

// good
const items = getItems();
const goSportsTeam = true;
const dragonball = 'z';
  • 13.3 Groupez tous vos const et ensuite tous vos let.

Pourquoi ? Ceci est utile lorsque plus tard vous devrez peut-être assigner une variable en fonction de l’une des variables précédemment assignées.

// 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;
  • 13.4 Assignez des variables là où vous en avez besoin, mais placez-les à un endroit raisonnable.

Pourquoi ? let et const ont une portée de bloc et non de fonction.

// 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;
}

Hoisting

  • 14.1 Les déclarations var sont hissées (hoisted) vers le haut de leur portée, mais leur affectation ne l’est pas. Les déclarations const et let bénéficient d’un nouveau concept appelé Zones Mortes Temporelles (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;
}
  • 14.2 Les expressions de fonction anonymes hissent leur nom de variable, mais pas l’affectation de la fonction.
function example() {
    console.log(anonymous); // => undefined

    anonymous(); // => TypeError anonymous is not a function

    var anonymous = function () {
    console.log('anonymous function expression');
    };
}
  • 14.3 Les expressions de fonction nommées hissent 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');
    }
}
  • 14.4 Les déclarations de fonction hissent leur nom et le corps de la fonction.
function example() {
    superPower(); // => Flying

    function superPower() {
    console.log('Flying');
    }
}

Opérateurs de Comparaison et Égalité (Comparison Operators & Equality)

  • 15.1 Utilisez === et !== au lieu de == et !=. eslint : eqeqeq

  • 15.2 Les instructions conditionnelles comme if évaluent leur expression en utilisant la coercition avec la méthode abstraite ToBoolean et suivent toujours ces règles simples :

  • Objects sont évalués à true
  • Undefined est évalué à false
  • Null est évalué à false
  • Booleans sont évalués à la valeur du booléen
  • Numbers sont évalués à false si +0, -0, ou NaN, sinon true
  • Strings sont évalués à false si c’est une chaîne vide '', sinon true
if ([0] && []) {
    // true
    // an array (even an empty one) is an object, objects will evaluate to true
}
  • 15.3 Utilisez des raccourcis.
// bad
if (name !== '') {
    // ...stuff...
}

// good
if (name) {
    // ...stuff...
}

// bad
if (collection.length > 0) {
    // ...stuff...
}

// good
if (collection.length) {
    // ...stuff...
}
  • 15.4 Pour plus d’informations, voir Truth Equality and JavaScript par Angus Croll.
  • 15.5 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).

Pourquoi ? Les déclarations lexicales sont visibles dans tout le bloc switch mais ne sont initialisées que lorsqu’elles sont assigné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.

eslint rules : no-case-declarations.

// 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 {}
    }
}
  • 15.7 Les opérateurs ternaires ne devraient pas être imbriqués et devraient généralement être des expressions sur une seule ligne.

eslint rules : 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;
  • 15.8 Évitez les instructions ternaires inutiles.

eslint rules : 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;

Blocs (Blocks)

  • 16.1 Utilisez des accolades avec tous les blocs 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;
}
// bad
if (test) {
    thing1();
    thing2();
}
else {
    thing3();
}

// good
if (test) {
    thing1();
    thing2();
} else {
    thing3();
}

Instructions de Contrôle (Control Statements)

  • 17.1 Si votre instruction de contrôle (if, while etc.) devient trop longue ou dépasse la longueur maximale de la ligne, chaque condition (groupée) peut être placée sur une nouvelle ligne. L’opérateur logique doit commencer la ligne.

Pourquoi ? Exiger des opérateurs au début de la ligne maintient les opérateurs alignés et suit un modèle similaire au chaînage de méthodes. Cela améliore également la lisibilité en rendant la logique complexe plus facile à suivre visuellement.

// bad
if ((foo === 123 || bar === 'abc') && doesItLookGoodWhenItBecomesThatLong() && isThisReallyHappening()) {
    thing1();
}

// bad
if (foo === 123 &&
    bar === 'abc') {
    thing1();
}

// bad
if (foo === 123
    && bar === 'abc') {
    thing1();
}

// bad
if (
    foo === 123 &&
    bar === 'abc'
) {
    thing1();
}

// good
if (
    foo === 123
    && bar === 'abc'
) {
    thing1();
}

// good
if (
    (foo === 123 || bar === 'abc')
    && doesItLookGoodWhenItBecomesThatLong()
    && isThisReallyHappening()
) {
    thing1();
}

// good
if (foo === 123 && bar === 'abc') {
    thing1();
}
  • 17.2 N’utilisez pas d’opérateurs de sélection à la place des instructions de contrôle.
// bad
!isRunning && startRunning();

// good
if (!isRunning) {
    startRunning();
}

Commentaires (Comments)

  • 18.1 Utilisez /** ... */ pour les commentaires multilignes. Incluez une description, spécifiez les types et les valeurs pour tous les paramètres et les valeurs de retour.
// bad
// make() returns a new element
// based on the passed in tag name
//
// @param {String} tag
// @return {Element} element
function make(tag) {

    // ...stuff...

    return element;
}

// good
/**
 * make() returns a new element
 * based on the passed in tag name
 *
 * @param {String} tag
 * @return {Element} element
 */
function make(tag) {

    // ...stuff...

    return element;
}
  • 18.2 Utilisez // pour les commentaires sur une seule ligne. Placez les commentaires sur une seule ligne sur une nouvelle ligne au-dessus du sujet du commentaire. Mettez une ligne vide avant le commentaire, sauf s’il est 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;
}
  • 18.3 Préfixer vos commentaires avec FIXME ou TODO aide les autres développeurs à comprendre rapidement si vous signalez un problème qui doit être revu ou si vous suggérez une solution qui doit être implémentée. Ceux-ci sont différents des commentaires réguliers car ils sont actionnables. Les actions sont FIXME : -- need to figure this out ou TODO : -- need to implement.

  • 18.4 Utilisez // FIXME : pour annoter les problèmes.

class Calculator extends Abacus {
    constructor() {
    super();

    // FIXME: shouldn't use a global here
    total = 0;
    }
}
  • 18.5 Utilisez // TODO : pour annoter les solutions aux problèmes.
class Calculator extends Abacus {
    constructor() {
    super();

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

Espaces (Whitespace)

// bad
function foo() {
∙∙∙∙const name;
}

// bad
function bar() {
const name;
}

// good
function baz() {
∙∙const name;
}
// 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',
});
// bad
if(isJedi) {
    fight ();
}

// good
if (isJedi) {
    fight();
}

// bad
function fight () {
    console.log ('Swooosh!');
}

// good
function fight() {
    console.log('Swooosh!');
}
// bad
const x=y+5;

// good
const x = y + 5;
  • 19.5 Terminez les fichiers par un seul saut de ligne.
// bad
(function (global) {
    // ...stuff...
})(this);
// bad
(function (global) {
    // ...stuff...
})(this);

// good
(function (global) {
    // ...stuff...
})(this);
// 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);
// 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;
// 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);
}
// bad
function bar( foo ) {
    return foo;
}

// good
function bar(foo) {
    return foo;
}

// bad
if ( foo ) {
    console.log(foo);
}

// good
if (foo) {
    console.log(foo);
}
// bad
const foo = [ 1, 2, 3 ];
console.log(foo[ 0 ]);

// good
const foo = [1, 2, 3];
console.log(foo[0]);
// bad
const foo = {clark: 'kent'};

// good
const foo = { clark: 'kent' };

Pourquoi ? Cela garantit la lisibilité et la maintenabilité.

// bad
const foo = 'Whatever national crop flips the window. The cartoon reverts within the screw. Whatever wizard constrains a helpful ally. The counterpart ascends!';

// 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 = 'Whatever national crop flips the window. The cartoon reverts within the screw. ' +
    'Whatever wizard constrains a helpful ally. The counterpart ascends!';

// good
$.ajax({
    method: 'POST',
    url: 'https://airbnb.com/',
    data: { name: 'John' },
})
    .done(() => console.log('Congratulations!'))
    .fail(() => console.log('You have failed this city.'));

Virgules (Commas)

// 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',
};

Pourquoi ? Cela conduit à des diffs git plus propres. De plus, les transpilateurs comme Babel supprimeront la virgule finale supplémentaire dans le code transpilé, ce qui signifie que vous n’avez pas à vous soucier du problème de virgule finale dans les navigateurs existants.

// bad - git diff without trailing comma
const hero = {
        firstName: 'Florence',
    lastName: 'Nightingale'
+    lastName: 'Nightingale',
+    inventorOf: ['coxcomb graph', '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',
];

Point-virgules (Semicolons)

// bad
(function () {
    const name = 'Skywalker'
    return name
})()

// good
(() => {
    const name = 'Skywalker';
    return name;
}());

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

Lire plus.

Conversion de Type et Coercition (Type Casting & Coercion)

  • 22.1 Effectuez la conversion de type au début de l’instruction.
  • 22.2 Strings :
// => this.reviewScore = 9;

// bad
const totalScore = this.reviewScore + '';

// good
const totalScore = String(this.reviewScore);
  • 22.3 Nombres : Utilisez Number pour le casting de type et parseInt toujours avec une base pour analyser les chaînes. eslint : radix
const inputValue = '4';

// bad
const val = new Number(inputValue);

// bad
const val = +inputValue;

// bad
const val = inputValue >> 0;

// bad
const val = parseInt(inputValue);

// good
const val = Number(inputValue);

// good
const val = parseInt(inputValue, 10);
  • 22.4 Si pour une raison quelconque vous faites quelque chose de fou et que parseInt est votre goulot d’étranglement et que vous devez utiliser Bitshift pour des raisons de performance, laissez un commentaire expliquant pourquoi et ce que vous faites.
// 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;
  • 22.5 Note : Soyez prudent lors de l’utilisation des opérations de bitshift. Les nombres sont représentés comme des valeurs 64 bits, mais les opérations de bitshift renvoient toujours un entier 32 bits (source). Le bitshift peut entraîner un comportement inattendu pour les valeurs entières supérieures à 32 bits. Discussion. Le plus grand entier signé de 32 bits est 2,147,483,647 :
2147483647 >> 0 //=> 2147483647
2147483648 >> 0 //=> -2147483648
2147483649 >> 0 //=> -2147483647
const age = 0;

// bad
const hasAge = new Boolean(age);

// good
const hasAge = Boolean(age);

// good
const hasAge = !!age;

Conventions de Nommage (Naming Conventions)

  • 23.1 Évitez les noms d’une seule lettre. Soyez descriptif avec votre nommage.
// bad
function q() {
    // ...stuff...
}

// good
function query() {
    // ..stuff..
}
// bad
const OBJEcttsssss = {};
const this_is_my_object = {};
function c() {}

// good
const thisIsMyObject = {};
function thisIsMyFunction() {}
// 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',
});
// bad
this.__firstName__ = 'Panda';
this.firstName_ = 'Panda';

// good
this._firstName = 'Panda';
  • 23.5 Ne stockez pas de références à this. Utilisez des fonctions fléchées ou Function#bind. jscs : disallowNodeTypes
// 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);
    };
}
  • 23.6 Si votre fichier exporte une seule classe, votre nom de fichier doit correspondre exactement au nom de votre classe.
// file contents
class CheckBox {
    // ...
}
export default CheckBox;

// in some other file
// bad
import CheckBox from './checkBox';

// bad
import CheckBox from './check_box';

// good
import CheckBox from './CheckBox';
  • 23.7 Utilisez le camelCase lorsque vous exportez par défaut une fonction. Votre nom de fichier doit être identique au nom de votre fonction.
function makeStyleGuide() {
}

export default makeStyleGuide;
  • 23.8 Utilisez le PascalCase lorsque vous exportez un singleton / une bibliothèque de fonctions / un objet vide.
const AirbnbStyleGuide = {
    es6: {
    }
};

export default AirbnbStyleGuide;

Accesseurs (Accessors)

  • 24.1 Les fonctions d’accès pour les propriétés ne sont pas obligatoires.
  • 24.2 N’utilisez pas de getters/setters JavaScript car ils provoquent des effets de bord inattendus et sont difficiles à tester, maintenir et raisonner. Au lieu de cela, si vous créez des fonctions d’accès, utilisez getVal() et setVal(‘hello’).
// bad
dragon.age();

// good
dragon.getAge();

// bad
dragon.age(25);

// good
dragon.setAge(25);
  • 24.3 Si la propriété est un booléen, utilisez isVal() ou hasVal().
// bad
if (!dragon.age()) {
    return false;
}

// good
if (!dragon.hasAge()) {
    return false;
}
  • 24.4 Il est acceptable de créer des fonctions get() et set(), mais soyez cohérent.
class Jedi {
    constructor(options = {}) {
    const lightsaber = options.lightsaber || 'blue';
    this.set('lightsaber', lightsaber);
    }

    set(key, val) {
    this[key] = val;
    }

    get(key) {
    return this[key];
    }
}

Événements (Events)

  • 25.1 Lorsque vous attachez des charges utiles de données à des événements (qu’il s’agisse d’événements DOM ou quelque chose de plus propriétaire comme les événements Backbone), passez un hash au lieu d’une valeur brute. Cela permet à un contributeur ultérieur d’ajouter plus de données à la charge utile de l’événement sans trouver et mettre à jour chaque gestionnaire pour l’événement. Par exemple, au lieu de :
// bad
$(this).trigger('listingUpdated', listing.id);

...

$(this).on('listingUpdated', (e, listingId) => {
    // do something with listingId
});

préférez :

// good
$(this).trigger('listingUpdated', { listingId: listing.id });

...

$(this).on('listingUpdated', (e, data) => {
    // do something with data.listingId
});

jQuery

// bad
const sidebar = $('.sidebar');

// good
const $sidebar = $('.sidebar');

// good
const $sidebarBtn = $('.sidebar-btn');
  • 26.2 Mettez en cache les recherches jQuery.
// bad
function setSidebar() {
    $('.sidebar').hide();

    // ...stuff...

    $('.sidebar').css({
    'background-color': 'pink'
    });
}

// good
function setSidebar() {
    const $sidebar = $('.sidebar');
    $sidebar.hide();

    // ...stuff...

    $sidebar.css({
    'background-color': 'pink'
    });
}
  • 26.3 Pour les requêtes DOM, utilisez Cascading $('.sidebar ul') ou parent > child $('.sidebar > ul'). jsPerf
  • 26.4 Utilisez find avec des requêtes d’objet jQuery scopées.
// bad
$('ul', '.sidebar').hide();

// bad
$('.sidebar').find('ul').hide();

// good
$('.sidebar ul').hide();

// good
$('.sidebar > ul').hide();

// good
$sidebar.find('ul').hide();

Compatibilité ECMAScript 5 (ECMAScript 5 Compatibility)

Styles ECMAScript 6 (ECMAScript 6 Styles)

  • 28.1 Ceci est une collection de liens vers les différentes fonctionnalités de ES6.
  1. Arrow Functions
  2. Classes
  3. Object Shorthand
  4. Object Concise
  5. Computed Object Properties
  6. Template Strings
  7. Destructuring
  8. Default Parameters
  9. Rest
  10. Array Spreads
  11. Let and Const
  12. Iterators and Generators
  13. Modules

Bibliothèque Standard (Standard Library)

La Bibliothèque Standard contient des utilitaires qui sont cassés mais conservés pour des raisons d’héritage.

  • 29.1 Utilisez Number.isNaN au lieu de isNaN.

Pourquoi ? isNaN contraint les valeurs non numériques en nombres, retournant true pour tout ce qui se convertit en NaN. Si ce comportement est souhaité, rendez-le explicite.

// bad
isNaN('1.2'); // false
isNaN('1.2.3'); // true

// good
Number.isNaN('1.2.3'); // false
Number.isNaN(Number('1.2.3')); // true
  • 29.2 Utilisez Number.isFinite au lieu de isFinite.

Pourquoi ? isFinite contraint les valeurs non numériques en nombres, retournant true pour tout ce qui se convertit en un nombre fini. Si ce comportement est souhaité, rendez-le explicite.

// bad
isFinite('2e3'); // true

// good
Number.isFinite('2e3'); // false
Number.isFinite(parseInt('2e3', 10)); // true

Tests (Testing)

function foo() {
    return true;
}
  • 30.2 Non, sérieusement :
  • Peu importe le framework de test que vous utilisez, vous devriez écrire des tests !
  • Essayez d’écrire beaucoup de petites fonctions pures et minimisez les endroits où les mutations se produisent.
  • Soyez prudent avec les stubs et les mocks - ils peuvent rendre vos tests plus fragiles.
  • Nous utilisons principalement mocha chez Airbnb. tape est aussi utilisé occasionnellement pour de petits modules séparés.
  • 100% de couverture de test est un bon objectif à viser, même s’il n’est pas toujours pratique à atteindre.
  • Chaque fois que vous corrigez un bug, écrivez un test de régression. Un bug corrigé sans test de régression se cassera presque certainement à nouveau à l’avenir.

Performance

Ressources (Resources)

Apprenez ES6

Lecture Obligatoire

Outils

  • Code Style Linters

Autres Guides de Style

Autres Styles

Lecture Complémentaire

Livres

Blogs

Podcasts

Dans la nature (In the Wild)

Ceci est une liste d’organisations qui utilisent ce guide de style. Envoyez-nous une pull request ou une issue, et nous vous ajouterons à la liste.

Traduction (Translation)

Ce guide de style est également disponible dans d’autres langues :

Le Guide du Guide de Style JavaScript (The JavaScript Style Guide Guide)

Discutez avec nous de JavaScript

Contributeurs (Contributors)

Licence (License)

(The MIT License)

Copyright (c) 2014-2016 Airbnb

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ‘Software’), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Modifications (Amendments)

Nous vous encourageons à forker ce guide et à modifier les règles pour qu’elles correspondent au guide de style de votre équipe. Ci-dessous, vous pouvez lister quelques modifications apportées au guide de style. Cela vous permet de mettre à jour périodiquement votre guide de style sans avoir à gérer les conflits de fusion (merge conflicts).

Reference

All rights reserved,未經允許不得隨意轉載
Généré avec Hugo
Thème Stack conçu par Jimmy