Руководство по стилю JavaScript для Airbnb — переведенная версия

JavaScript

Руководство по стилю JavaScript для Airbnb() {

В основном разумный подход к JavaScript

Уведомление: В этом руководстве предполагается, что вы используетеBabel, и требует, чтобы вы использовали или эквивалентноbabel-preset-airbnb. Также предположим, что вы установили в своем приложении или эквивалентныйairbnb-browser-shimsиз

shims/polyfills

содержание

  1. Types
  2. References
  3. Objects
  4. Arrays
  5. Destructuring
  6. Strings
  7. Functions
  8. Arrow Functions
  9. Classes & Constructors
  10. Modules
  11. Iterators and Generators
  12. Properties
  13. Variables
  14. Hoisting
  15. Comparison Operators & Equality
  16. Blocks
  17. Control Statements
  18. Comments
  19. Whitespace
  20. Commas
  21. Semicolons
  22. Type Casting & Coercion
  23. Naming Conventions
  24. Accessors
  25. Events
  26. jQuery
  27. ECMAScript 5 Compatibility
  28. ECMAScript 6+ (ES 2015+) Styles
  29. Standard Library
  30. Testing
  31. Performance
  32. Resources
  33. In the Wild
  34. Translation
  35. The JavaScript Style Guide Guide
  36. Chat With Us About JavaScript
  37. Contributors
  38. License
  39. Amendments

Types

  • 1.1Примитивные типы: вы можете напрямую получить значение примитивного типа
    • string
    • number
    • boolean
    • null
    • undefined
    • symbol
    const foo = 1;
    let bar = foo;
    bar = 9;
    console.log(foo, bar); // => 1, 9
    
    • Символы не могут быть правильно заполнены полифиллом. Таким образом, в среде [браузере], которая изначально не поддерживает тип символа, этот тип символа использовать не следует.

  • 1.2Сложный тип: присвоение сложного типа является ценностью получения его ссылки. Эквивалент прохождения
    • object
    • array
    • function
    const foo = [1, 2];
    const bar = foo;
    bar[0] = 9;
    console.log(foo[0], bar[0]); // => 9, 9
    

References

  • 2.1Во всех заданиях используетсяconst, избегать использованияvar. eslint: prefer-const, no-const-assign

    Почему? Поскольку это гарантирует, что вы не измените исходное значение, повторные ссылки могут привести к ошибкам и коду, который трудно понять.

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

  • 2.2Если вам необходимо переназначить параметр, используйтеlet, вместоvar. eslint: no-var

    Почему потому чтоletимеет блочную область видимости иvarобласть действия на функциональном уровне

    // bad
    var count = 1;
    if (true) {
      count += 1;
    }
    
    // good, use the let.
    let count = 1;
    if (true) {
      count += 1;
    }
    

  • 2.3Уведомление:let,constимеют блочную область видимости

    // const 和 let 都只存在于它定义的那个块级作用域
    {
      let a = 1;
      const b = 1;
    }
    console.log(a); // ReferenceError
    console.log(b); // ReferenceError
    

Objects

  • 3.1Создавайте объекты с помощью литералов.eslint:no-new-object

    // bad
    const item = new Object();
    
    // good
    const item = {};
    

  • 3.2При создании объекта с динамическими именами свойств используйте вычисляемые имена свойств.

    Почему?Это позволяет разместить все свойства, которые вы определяете, в одном месте объекта.

    
    function getKey(k) {
      return `a key named ${k}`;
    }
    
    // bad
    const obj = {
      id: 5,
      name: 'San Francisco',
    };
    obj[getKey('enabled')] = true;
    
    // good getKey('enabled')是动态属性名
    const obj = {
      id: 5,
      name: 'San Francisco',
      [getKey('enabled')]: true,
    };
    

  • 3.3Сокращение с объектными методами.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;
      },
    };
    

  • 3.4Аббревиатура со значением свойства.eslint:object-shorthand

    Почему? Это меньше написано и более читабельно

    const lukeSkywalker = 'Luke Skywalker';
    
    // bad
    const obj = {
      lukeSkywalker: lukeSkywalker,
    };
    
    // good
    const obj = {
      lukeSkywalker,
    };
    

  • 3.5Поместите все свои сокращения в начало объявления объекта.

    Почему?Это также поможет понять, какие свойства сокращены.

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

  • 3.6Используйте кавычки только для недопустимых токенов''. eslint: quote-props

    Почему?Обычно мы думаем, что этот способ субъективно легко читается. Он оптимизирует подсветку кода, а страницы легче сжимать многими движками JS.

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

  • 3.7Не звоните напрямуюObject.prototypeметод выше, напримерhasOwnProperty, propertyIsEnumerable, isPrototypeOf.

    Почему?На некоторых проблемных объектах эти методы могут быть заблокированы, например:{ hasOwnProperty: false }- или это пустой объектObject.create(null)

    // bad
    console.log(object.hasOwnProperty(key));
    
    // good
    console.log(Object.prototype.hasOwnProperty.call(object, key));
    
    // best
    const has = Object.prototype.hasOwnProperty; // 在模块作用内做一次缓存
    /* or */
    import has from 'has'; // https://www.npmjs.com/package/has
    // ...
    console.log(has.call(object, key));
    

  • 3.8При мелком копировании объектов рекомендуется использовать оператор распространения [ т.е....оператор] вместоObject.assign. При получении нескольких свойств, указанных объектом, используйте оставшийся оператор деструктуризации объекта [также...оператор] лучше.
    • Этот абзац не очень легко перевести, и вы можете понять это, взглянув на следующий пример. ^.^
// 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 es6扩展运算符 ...
const original = { a: 1, b: 2 };
// 浅拷贝
const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }

// rest 赋值运算符
const { a, ...noA } = copy; // noA => { b: 2, c: 3 }

Arrays

  • 4.1Присвойте буквальное значение. эслинт:no-array-constructor

    // bad
    const items = new Array();
    
    // good
    const items = [];
    

  • 4.2использоватьArray#pushВместо добавления значения непосредственно в массив.

    const someStack = [];
    
    // bad
    someStack[someStack.length] = 'abracadabra';
    
    // good
    someStack.push('abracadabra');
    

  • 4.3Используйте оператор распространения, чтобы сделать неглубокую копию массива, аналогичную приведенной выше неглубокой копии объекта.

    // bad
    const len = items.length;
    const itemsCopy = [];
    let i;
    
    for (i = 0; i < len; i += 1) {
      itemsCopy[i] = items[i];
    }
    
    // good
    const itemsCopy = [...items];
    

  • 4.4использовать...оператор вместоArray.fromдля преобразования итерируемого объекта в массив.

    const foo = document.querySelectorAll('.foo');
    
    // good
    const nodes = Array.from(foo);
    
    // best
    const nodes = [...foo];
    

  • 4.5использоватьArray.fromдля преобразования объекта, подобного массиву, в массив.

    const arrLike = { 0: 'foo', 1: 'bar', 2: 'baz', length: 3 };
    
    // bad
    const arr = Array.prototype.slice.call(arrLike);
    
    // good
    const arr = Array.from(arrLike);
    

  • 4.6использоватьArray.fromвместо...оператор для обхода карты. Потому что это позволяет избежать создания временного массива.

    // bad
    const baz = [...foo].map(bar);
    
    // good
    const baz = Array.from(foo, bar);
    

  • 4.7Используйте оператор return в функции обратного вызова метода массива. Если тело функции состоит из инструкции, возвращающей выражение, и это выражение не имеет побочных эффектов, то в это время можно проигнорировать возврат.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 - 没有返回值, 因为在第一次迭代后acc 就变成undefined了
    [[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) => {
      const flatten = acc.concat(item);
      acc[index] = flatten;
    });
    
    // good
    [[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) => {
      const flatten = acc.concat(item);
      acc[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;
    });
    

  • 4.8Если в массиве много строк, в массиве[после и]Разрыв строки перед. См. пример ниже

    // bad
    const arr = [
      [0, 1], [2, 3], [4, 5],
    ];
    
    const objectInArray = [{
      id: 1,
    }, {
      id: 2,
    }];
    
    const numberInArray = [
      1, 2,
    ];
    
    // good
    const arr = [[0, 1], [2, 3], [4, 5]];
    
    const objectInArray = [
      {
        id: 1,
      },
      {
        id: 2,
      },
    ];
    
    const numberInArray = [
      1,
      2,
    ];
    

Destructuring

  • 5.1Используйте присваивание деструктуризации объекта, чтобы получить и использовать значение одного или нескольких свойств объекта. эслинт:prefer-destructuring

    Почему?Деструктуризация сохраняет временные значения/ссылки для этих свойств

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

  • 5.2Деструктуризация с помощью массивов.

    const arr = [1, 2, 3, 4];
    
    // bad
    const first = arr[0];
    const second = arr[1];
    
    // good
    const [first, second] = arr;
    

  • 5.3Несколько возвращаемых значений используют деструктурирование объекта, а не деструктурирование данных.

    Зачем? Вы можете добавить новые свойства или изменить порядок переменных позже, не нарушая исходный вызов.

    // bad
    function processInput(input) {
      // 然后就是见证奇迹的时刻
      return [left, right, top, bottom];
    }
    
    // 调用者需要想一想返回值的顺序
    const [left, __, top] = processInput(input);
    
    // good
    function processInput(input) {
      // oops, 奇迹又发生了
      return { left, right, top, bottom };
    }
    
    // 调用者只需要选择他想用的值就好了
    const { left, top } = processInput(input);
    

Strings

  • 6.1использовать одинарные кавычки для строк''. эслинт:quotes

    // bad
    const name = "Capt. Janeway";
    
    // bad - 样例应该包含插入文字或换行
    const name = `Capt. Janeway`;
    
    // good
    const name = 'Capt. Janeway';
    

  • 6.2Строки длиннее 100 символов не должны объединяться в несколько строк со строкой.

    Почему?Неработающие строки плохо работают и делают код менее доступным для поиска.

    // 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.';
    

  • 6.3Организуйте программируемые строки с помощью строковых шаблонов вместо конкатенации строк. эслинт:prefer-template template-curly-spacing

    Зачем?Стандартные строки более удобочитаемы, синтаксически лаконичны, а строки интерполируют параметры.

    // 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.4никогда не используйте в строкеeval(), он ящик Пандоры. эслинт:no-eval

  • 6.5Не используйте ненужные escape-символы. эслинт:no-useless-escape

    Почему?Обратные слэши плохо читаются, поэтому они появляются только тогда, когда их нужно использовать.

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

Functions

  • 7.1用命名函数表达式而不是函数声明。 эслинт:func-style

    Выражение функции: const func = function () {}

    Объявление функции: function func() {}

    Почему?Функции объявляются с расширенной областью видимости, что означает, что на функции легко (слишком легко) ссылаться в файле до того, как они будут определены. Это вредит читабельности кода и ремонтопригодности. Если вы найдете функцию, которая настолько велика и сложна, что мешает пониманию остальной части файла, возможно, пришло время выделить функцию в отдельный модуль. Не забудьте указать выражение явно, независимо от того, выводится ли имя из детерминированной переменной или нет, это устраняет все предположения, сделанные анонимными функциями в неправильном стеке вызовов, что часто встречается в современных браузерах и компиляторах, таких как Babel. в (Discussion)

    Почему?В этом абзаце не понимается сцена,где возникает эта ошибка,поэтому его можно перевести только напрямую.ПрикрепилоригинальныйПочему? Объявления функций поднимаются, а это означает, что легко — слишком просто — сослаться на функцию до того, как она будет определена в файле. Это вредит удобочитаемости и удобству сопровождения. с пониманием остальной части файла, то, возможно, пришло время извлечь его в свой собственный модуль!Не забудьте явно назвать выражение, независимо от того, выводится ли имя из содержащей его переменной (что часто бывает в современных браузерах или при использовании компиляторов, таких как Babel). Это устраняет любые предположения, сделанные о стеке вызовов Error. (Discussion)

    // bad
    function foo() {
      // ...
    }
    
    // bad
    const foo = function () {
      // ...
    };
    
    // good
    // lexical name distinguished from the variable-referenced invocation(s)
    // 函数表达式名和声明的函数名是不一样的
    const short = function longUniqueMoreDescriptiveLexicalFoo() {
      // ...
    };
    

  • 7.2Заключите немедленно выполняемую функцию в круглые скобки. эслинт:wrap-iife

    Почему сразу вызывается функция expression = IIFE Почему?Немедленно вызываемое функциональное выражение представляет собой единицу — оберните его вызывающей стороной (круглые скобки), и в круглых скобках вы можете выразить это ясно. Почему?Примечание: в модульном мире вам вряд ли понадобится IIFE.

    // immediately-invoked function expression (IIFE)
    (function () {
      console.log('Welcome to the Internet. Please follow me.');
    }());
    

  • 7.3Не объявляйте функции внутри нефункциональных блоков (if, while и т. д.). Назначьте эту функцию переменной. Браузеры позволяют это сделать, но браузеры анализируют это по-разному, что является плохой новостью. 【Смотрите подробностиno-loop-func] если:no-loop-func

  • 7.4 Note:В ECMA-262 [блокblock] определяется как: серия операторов, но объявление функции не является оператором. Функциональное выражение является оператором.

    // bad
    if (currentUser) {
      function test() {
        console.log('Nope.');
      }
    }
    
    // good
    let test;
    if (currentUser) {
      test = () => {
        console.log('Yup.');
      };
    }
    

  • 7.5Не используйте егоargumentsИменованные параметры. Его приоритет выше, чем у каждой функции, с которой поставляетсяargumentsобъект, что приводит к собственномуargumentsзначение перезаписывается

    // bad
    function foo(name, options, arguments) {
      // ...
    }
    
    // good
    function foo(name, options, args) {
      // ...
    }
    

  • 7.6Не используйтеarguments, в остальном синтаксисе...заменять. эслинт:prefer-rest-params

    Why? ...Уточните, какой параметр вы хотите использовать. А оставшийся параметр - это настоящий массив, а не массивarguments

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

  • 7.7Используйте синтаксис параметров по умолчанию вместо переназначения параметров внутри функций.

    // really bad
    function handleThings(opts) {
      // 不, 我们不该改arguments
      // 第二: 如果 opts 的值为 false, 它会被赋值为 {}
      // 虽然你想这么写, 但是这个会带来一些细微的bug
      opts = opts || {};
      // ...
    }
    
    // still bad
    function handleThings(opts) {
      if (opts === void 0) {
        opts = {};
      }
      // ...
    }
    
    // good
    function handleThings(opts = {}) {
      // ...
    }
    

  • 7.8Параметры по умолчанию позволяют избежать побочных эффектов

    Почему?Он будет сбит с толку, как это ниже, равно несколько, это нужно думать.

    var b = 1;
    // bad
    function count(a = b++) {
      console.log(a);
    }
    count();  // 1
    count();  // 2
    count(3); // 3
    count();  // 3
    

  • 7.9Поместите назначения параметров по умолчанию в конец

    // bad
    function handleThings(opts = {}, name) {
      // ...
    }
    
    // good
    function handleThings(name, opts = {}) {
      // ...
    }
    

  • 7.10Не создавайте функции с конструкторами функций. эслинт:no-new-func

    Почему?Создание функции таким образом было бы похоже на строку eval(), которая открыла бы лазейку.

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

  • 7.11В части сигнатуры функции должны быть пробелы. эслинт:space-before-function-paren space-before-blocks

    Почему?Единообразие и отсутствие необходимости добавлять/удалять пробелы при добавлении/удалении имени

    // bad
    const f = function(){};
    const g = function (){};
    const h = function() {};
    
    // good
    const x = function () {};
    const y = function a() {};
    

  • 7.12Не изменять параметры.no-param-reassign

    Почему? Манипулирование объектом параметра может привести к неожиданным побочным эффектам для первоначального вызывающего объекта. То есть не меняйте структуру данных параметра, сохраняйте исходное значение и структуру данных параметра.

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

  • 7.13Не переназначайте параметры. эслинт:no-param-reassign

    Почему?Переназначение параметра может привести к непредвиденному поведению, особенно дляarguments. Это также приводит к проблемам с оптимизацией, особенно в 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) {
      // ...
    }
    

  • 7.14использоватьspreadоператор...去调用多变的函数更好。 эслинт:prefer-spread

    Почему? Так понятнее, вам не нужно предоставлять контекст, и вы не можете легко использоватьapplyсочинятьnew

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

  • 7.15Вызов или написание функции с несколькими аргументами следует выполнять так же, как и любой другой многострочный код в этом руководстве: каждая строка значений содержит один аргумент, и каждая строка заканчивается запятой.

    // bad
    function foo(bar,
                 baz,
                 quux) {
      // ...
    }
    
    // good 缩进不要太过分
    function foo(
      bar,
      baz,
      quux,
    ) {
      // ...
    }
    
    // bad
    console.log(foo,
      bar,
      baz);
    
    // good
    console.log(
      foo,
      bar,
      baz,
    );
    

Arrow Functions

  • 8.1Используйте выражения со стрелками, когда необходимо использовать выражения функций (в функциях обратного вызова). эслинт:prefer-arrow-callback, arrow-spacing

    Почему? Он создал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;
    });
    

  • 8.2Если тело функции состоит извыражениеСостав оператора, удаление фигурных скобок и возврат. В противном случае продолжайте с фигурными скобками иreturnутверждение. эслинт:arrow-parens, arrow-body-style

    Почему?Синтаксический сахар, легко читаемый, когда несколько функций объединены в цепочку.

    // 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
    }));
    
    // 表达式有副作用就不要用隐式return
    function foo(callback) {
      const val = callback();
      if (val === true) {
        // Do something if callback returns true
      }
    }
    
    let bool = false;
    
    // bad
    // 这种情况会return bool = true, 不好
    foo(() => bool = true);
    
    // good
    foo(() => {
      bool = true;
    });
    

  • 8.3Если выражение состоит из нескольких строк, удобнее заключить его в круглые скобки.

    Почему?Это ясно показывает начало и конец функции

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

  • 8.4Если ваша функция имеет только один параметр и в теле функции нет фигурных скобок, удалите круглые скобки. В противном случае параметры всегда заключаются в круглые скобки. Примечание. Можно постоянно использовать круглые скобки, просто настройтевариант "всегда" for eslint. eslint: arrow-parens

    Почему? Это менее запутанно. На самом деле здесь нет грамматического ударения. Просто сохраняйте тот же стиль.

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

  • 8.5Избегайте стрелочных функций (=>) и оператор сравнения (<=, >=) обфускация.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;
    };
    

  • 8.6在隐式return中强制约束函数体的位置, 就写在箭头后面。 эслинт:implicit-arrow-linebreak

    // bad
    (foo) =>
      bar;
    
    (foo) =>
      (bar);
    
    // good
    (foo) => bar;
    (foo) => (bar);
    (foo) => (
       bar
    )
    

Classes & Constructors

  • 9.1обычно используетсяclass, чтобы избежать прямого манипулированияprototype

    Why? classСинтаксис стал более лаконичным и понятным.

    // 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использоватьextendsреализовать наследование

    Зачем? Это встроенный способ унаследовать функциональность прототипа, не нарушая его.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Методы могут вернутьсяthisреализовать цепочку методов

    // 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Можно написать собственный метод toString(), если он работает и не имеет побочных эффектов.

    class Jedi {
      constructor(options = {}) {
        this.name = options.name || 'no name';
      }
    
      getName() {
        return this.name;
      }
    
      toString() {
        return `Jedi - ${this.getName()}`;
      }
    }
    

  • 9.5Если не указано, класс имеет конструктор по умолчанию. Пустой конструктор или просто конструктор, представляющий родительский класс, не требуется. эслинт: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';
      }
    }
    

  • 9.6Избегайте дублирования членов класса. эслинт:no-dupe-class-members

    Почему?Дубликаты членов класса будут молча выполнять последний - дублирование само по себе является ошибкой

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

  • 9.7Если для внешней библиотеки или фреймворка не требуется конкретный нестатический метод, методы класса должны использоватьthisИли превратиться в статический метод.

Будучи методом экземпляра, он должен указывать на то, что он ведет себя по-разному в зависимости от свойств получателя. эслинт:class-methods-use-this

```javascript
// bad
class Foo {
  bar() {
    console.log('bar');
  }
}

// good - this 被使用了 
class Foo {
  bar() {
    console.log(this.bar);
  }
}

// good - constructor 不一定要使用this
class Foo {
  constructor() {
    // ...
  }
}

// good - 静态方法不需要使用 this
class Foo {
  static bar() {
    console.log('bar');
  }
}
```

Modules

  • 10.1использовать(import/export) модуль вместо стандартной модульной системы. Вы всегда можете переключиться на предпочитаемую модульную систему.

    Почему Модульность — это будущее, давайте начнем прямо сейчас.

    // 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Не используйте подстановочные знаки импорта, т.е.*Сюда

    Почему? Это гарантирует, что у вас будет единый экспорт по умолчанию.

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

  • 10.3Не экспортировать напрямую из импорта

    Почему? Хотя одна строка краткая, есть четкий способ импорта и четкий способ экспорта для обеспечения согласованности.

    // bad
    // filename es6.js
    export { es6 as default } from './AirbnbStyleGuide';
    
    // good
    // filename es6.js
    import { es6 } from './AirbnbStyleGuide';
    export default es6;
    

  • 10.4Путь импортируется только один раз.

eslint: no-duplicate-imports> Почему? Импорт нескольких строк по одному и тому же пути усложняет сопровождение кода.

```javascript
// 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';
```

  • 10.5не экспортировать изменяемые вещи

eslint: import/no-mutable-exports> Почему Обычно следует избегать вариаций, особенно если вы экспортируете изменяемые привязки. Хотя этот метод может потребоваться в некоторых сценариях, в общем случае следует экспортировать константы.

```javascript
// bad
let foo = 3;
export { foo }

// good
const foo = 3;
export { foo }
```

  • 10.6В одном модуле экспорта используйтеexport defaultлучше.

eslint: import/prefer-default-export

> Why? 鼓励使用更多文件,每个文件只做一件事情并导出,这样可读性和可维护性更好。

```javascript
// bad
export function foo() {}

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

  • 10.7 importперед всеми другими заявлениями.

eslint: import/first> Почему?importПоместите его вверху, чтобы предотвратить неожиданное поведение.

```javascript
// bad
import foo from 'foo';
foo.init();

import bar from 'bar';

// good
import foo from 'foo';
import bar from 'bar';

foo.init();
```

  • 10.8Многострочный импорт должен иметь отступ, как многострочные массивы и литералы объектов.

    // bad
    import {longNameA, longNameB, longNameC, longNameD, longNameE} from 'path';
    
    // good
    import {
      longNameA,
      longNameB,
      longNameC,
      longNameD,
      longNameE,
    } from 'path';
    

eslint: import/no-webpack-loader-syntax> Почему?После того, как синтаксис Webpack используется для связывания кода с модулем связывания в импорте. предпочтительно вwebpack.config.jsНапишите синтаксис загрузчика webpack в

```javascript
// 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 and Generators

  • 11.1Не используйте итераторы. Вместо этого используйте расширенные функции JavaScriptfor-in,for-of. эслинт:no-iterator no-restricted-syntax

    Почему? Это подчеркивает наше непреложное правило. Легче иметь дело с чистыми функциями, возвращающими значения, чем с побочными эффектами.

    Почему? Используйте эти методы итерации для массивов:map() / every() / filter() / find() / findIndex() / reduce() / some()/ ... , используя эти методы объектаObject.keys() / Object.values() / Object.entries()для создания массива, чтобы вы могли перебирать объекты.

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

  • 11.2Не используйте генератор сейчас

    Почему? Он плохо поддерживается на es5.

  • 11.3Если вы должны использовать его, или вы игнорируетенаше предложение, убедитесь, что сигнатуры их функций правильно расположены. эслинт:generator-star-spacing

    Why? functionа также*это то же ключевое слово понятия -*нетfunctionмодификатор,function*это иfunctionразличные уникальные структуры

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

Properties

  • 12.1Используйте запись через точку при доступе к свойствам.eslint:dot-notation

    const luke = {
      jedi: true,
      age: 28,
    };
    
    // bad
    const isJedi = luke['jedi'];
    
    // good
    const isJedi = luke.jedi;
    

  • 12.2Используйте квадратные скобки, когда выбранное свойство является переменной[]Выбирать

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

  • 12.3Используйте оператор возведения в степень при возведении в степень**. эслинт:no-restricted-properties.

    // bad
    const binary = Math.pow(2, 10);
    
    // good
    const binary = 2 ** 10;
    

Variables

  • 13.1использоватьconstилиletобъявить переменные. Невыполнение этого требования приведет к глобальным переменным. Мы хотим избежать загрязнения глобального пространства имен. Начальник нас об этом предупредил. эслинт:no-undef prefer-const

    // bad
    superPower = new SuperPower();
    
    // good
    const superPower = new SuperPower();
    

  • 13.2Каждая переменная используетconstилиlet . эслинт:one-var

    Почему? Таким образом легко объявлять новые переменные, вам не нужно думать о том, чтобы поставить;заменяется,, или введите другую вариацию только с пунктуацией. Этот подход также позволяет выполнять пошагово каждый оператор объявления во время отладки, а не пропускать все объявления сразу.

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

  • 13.3 constсобрать,letсобрать

    Почему? Это полезно, когда вам нужно присвоить новую переменную, которая зависит от ранее назначенной переменной.

    // 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Объявляйте переменные там, где они вам нужны, но в разумных местах

    Why? letа такжеconstоба блочные, а не функциональные

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

  • 13.5Не используйте назначение переменной ссылки. эслинт:no-multi-assign

    Почему?Присвоение цепочке переменных создает неявные глобальные переменные.

    // bad
    (function example() {
      // JavaScript 将这一段解释为
      // let a = ( b = ( c = 1 ) );
      // let 只对变量 a 起作用; 变量 b 和 c 都变成了全局变量
      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
    
    // `const` 也是如此
    

  • 13.6Не используйте унарный оператор увеличения/уменьшения (++,--).no-plusplus

    Почему?Согласно документации eslint, унарные операторы увеличения и уменьшения подлежат автоматической вставке точки с запятой и могут вызывать тихие ошибки в приложениях, где значения увеличиваются или уменьшаются. использоватьnum + = 1вместоnum ++илиnum ++Заявления, выражающие ваши ценности, также более выразительны. Подавление унарных операторов инкремента и декремента также предотвращает непреднамеренное предварительное увеличение/уменьшение значений, что также может привести к непредвиденному поведению в вашей программе.

      // bad
    
      const array = [1, 2, 3];
      let num = 1;
      num++;
      --num;
    
      let sum = 0;
      let truthyCount = 0;
      for (let i = 0; i < array.length; i++) {
        let value = array[i];
        sum += value;
        if (value) {
          truthyCount++;
        }
      }
    
      // good
    
      const array = [1, 2, 3];
      let num = 1;
      num += 1;
      num -= 1;
    
      const sum = array.reduce((a, b) => a + b, 0);
      const truthyCount = array.filter(Boolean).length;
    

  • 13.7При присвоении значения избегайте=Новые строки до/после. Если ваш оператор присваивания превышаетmax-len, затем заключить значение в круглые скобки и перенести его на новую строку. эслинтoperator-linebreak.

    Почему?=Соседние новички могут легко запутать это заявление о назначении.

    // bad
    const foo =
      superLongLongLongLongLongLongLongLongFunctionName();
    
    // bad
    const foo
      = 'superLongLongLongLongLongLongLongLongString';
    
    // good
    const foo = (
      superLongLongLongLongLongLongLongLongFunctionName()
    );
    
    // good
    const foo = 'superLongLongLongLongLongLongLongLongString';
    

  • 13.8Неиспользуемые переменные не допускаются. эслинт:no-unused-vars

    Почему?Объявленная, но неиспользуемая переменная больше похожа на ошибку из-за незавершенного рефакторинга. Такие переменные, встречающиеся в коде, могут запутать читателя.

    // bad
    
    var some_unused_var = 42;
    
    // 写了没用
    var y = 10;
    y = 5;
    
    // 变量改了自己的值,也没有用这个变量
    var z = 0;
    z = z + 1;
    
    // 参数定义了但未使用
    function getX(x, y) {
        return x;
    }
    
    // good
    function getXPlusY(x, y) {
      return x + y;
    }
    
    var x = 1;
    var y = a + 2;
    
    alert(getXPlusY(x, y));
    
    // 'type' 即使没有使用也可以可以被忽略, 因为这个有一个 rest 取值的属性。
    // 这是从对象中抽取一个忽略特殊字段的对象的一种形式
    var { type, ...coords } = data;
    // 'coords' 现在就是一个没有 'type' 属性的 'data' 对象
    

Hoisting

  • 14.1 varОбъявление перемещается в начало своей области, а присваиваемое им значение не продвигается вперед.constа такжеletбыла дана новая концепция призванияTemporal Dead Zones - Временные мертвые зоны (TDZ). Важно знать, почемуtypeof больше не безопасен.

    // 我们知道这个不会工作,假设没有定义全局的notDefined
    function example() {
      console.log(notDefined); // => throws a ReferenceError
    }
    
    // 在你引用的地方之后声明一个变量,他会正常输出是因为变量作用域上升。
    // 注意: declaredButNotAssigned的值没有上升
    function example() {
      console.log(declaredButNotAssigned); // => undefined
      var declaredButNotAssigned = true;
    }
    
    // 解释器把变量声明提升到作用域最前面,
    // 可以重写成如下例子, 二者意义相同
    function example() {
      let declaredButNotAssigned;
      console.log(declaredButNotAssigned); // => undefined
      declaredButNotAssigned = true;
    }
    
    // 用 const, let就不一样了
    function example() {
      console.log(declaredButNotAssigned); // => throws a ReferenceError
      console.log(typeof declaredButNotAssigned); // => throws a ReferenceError
      const declaredButNotAssigned = true;
    }
    

  • 14.2анонимные функциональные выражения иvarТакая же ситуация

    function example() {
      console.log(anonymous); // => undefined
    
      anonymous(); // => TypeError anonymous is not a function
    
      var anonymous = function () {
        console.log('anonymous function expression');
      };
    }
    

  • 14.3Выражение именованной функции продвигает имя своей переменной, а не имя функции или тело функции.

    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');
      };
    }
    
    // 函数名和变量名一样是也如此
    function example() {
      console.log(named); // => undefined
    
      named(); // => TypeError named is not a function
    
      var named = function named() {
        console.log('named');
      };
    }
    

  • 14.4Объявления функций поднимают имя функции и тело функции.

    function example() {
      superPower(); // => Flying
    
      function superPower() {
        console.log('Flying');
      }
    }
    
  • Подробнее см.JavaScript Scoping & Hoisting by Ben Cherry.

Comparison Operators & Equality

  • 15.1использовать===а также!==вместо==а также!=. eslint: eqeqeq

  • 15.2Условные операторы, такие как операторы if, используют обязательный абстрактный метод ToBoolean для оценки своих выражений и всегда следуют этим простым правилам:

    • ObjectsРассчитано какtrue
    • UndefinedРассчитано какfalse
    • NullРассчитано какfalse
    • BooleansРассчитано какthe value of the boolean
    • Numbers
      • +0, -0, or NaNРассчитано какfalse
      • разноеtrue
    • Strings
      • ''Рассчитано какfalse
      • разноеtrue
    if ([0] && []) {
      // true
      // 数组(即使是空数组)是对象,对象会计算成true
    }
    

  • 15.3Булевы значения сокращены, а строки и числа явно сравниваются между собой.

    // bad
    if (isValid === true) {
      // ...
    }
    
    // good
    if (isValid) {
      // ...
    }
    
    // bad
    if (name) {
      // ...
    }
    
    // good
    if (name !== '') {
      // ...
    }
    
    // bad
    if (collection.length) {
      // ...
    }
    
    // good
    if (collection.length > 0) {
      // ...
    }
    

  • 15.5существуетcaseа такжеdefaultИспользуйте фигурные скобки в предложении, чтобы создать область, содержащую объявления синтаксиса (например,let, const, function, and class). eslint rules: no-case-declarations.

    Почему?switchвидны в блоке кода, но он будет инициализирован только тогда, когда он будет выделен.caseГенерируется при выполнении. когда несколькоcaseПри попытке определить то же самое положение о проблеме

    // 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.6Окружающие тернарные выражения не должны быть вложенными, обычно это однострочные выражения.

    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.7Избегайте нежелательных тернарных выражений

    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;
    

  • 15.8Используйте круглые скобки, чтобы смешать эти операторы. Только когда стандартные арифметические операторы (+, -, *, & /), а когда их приоритет очевиден, их можно не заключать в круглые скобки. эслинт:no-mixed-operators

    Почему?Это улучшает читабельность и проясняет намерения разработчика.

    // bad
    const foo = a && b < 0 || c > 0 || d + 1 === 0;
    
    // bad
    const bar = a ** b - 5 % d;
    
    // bad
    // 别人会陷入(a || b) && c 的迷惑中
    if (a || b && c) {
      return d;
    }
    
    // good
    const foo = (a && b < 0) || c > 0 || (d + 1 === 0);
    
    // good
    const bar = (a ** b) - (5 % d);
    
    // good
    if (a || (b && c)) {
      return d;
    }
    
    // good
    const bar = a + b / c * d;
    

Blocks

  • 16.1用大括号包裹多行代码块。 эслинт:nonblock-statement-body-position

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

  • 16.2 ifвыразительныйelseа такжеifЗакрывающая фигурная скобка находится на одной строке. эслинт:brace-style

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

  • 16.3еслиifзаявление всегда нужно использоватьreturnвозвращение, последующиеelseВам не нужно писать.ifблок содержитreturn, за этимelse ifБлок также содержитreturn, тогда ты можешьreturnразделен на несколькоifв блоке операторов. эслинт:no-else-return

    // bad
    function foo() {
      if (x) {
        return x;
      } else {
        return y;
      }
    }
    
    // bad
    function cats() {
      if (x) {
        return x;
      } else if (y) {
        return y;
      }
    }
    
    // bad
    function dogs() {
      if (x) {
        return x;
      } else {
        if (y) {
          return y;
        }
      }
    }
    
    // good
    function foo() {
      if (x) {
        return x;
      }
    
      return y;
    }
    
    // good
    function cats() {
      if (x) {
        return x;
      }
    
      if (y) {
        return y;
      }
    }
    
    // good
    function dogs(x) {
      if (x) {
        if (z) {
          return y;
        }
      } else {
        return z;
      }
    }
    

Control Statements

  • 17.1Когда ваш управляющий оператор (if, whileи т. д.) слишком длинный или превышает максимальный предел длины, поместите каждое (групповое) условие оценки на отдельной строке. Логические операторы располагаются в начале строки.

    Зачем?Размещая логические операторы в начале строки, мы сохраняем выравнивание операторов в соответствии со связанными функциями. Это улучшает читаемость и облегчает просмотр сложной логики.

    // 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Не заменяйте операторы управления операторами выбора.

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

⬆ вернуться к началу

Comments

  • 18.1Для многострочных комментариев/** ... */

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

  • 18.2однострочный комментарий//, поместите однострочный комментарий над закомментированной областью. Если комментарий находится не на первой строке, то комментарию предшествует пустая строка.

    // 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Все комментарии начинаются с пустого для удобства чтения. эслинт: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;
    }
    

  • 18.4использовать перед комментариемFIXME'或Префикс TODO, который помогает другим разработчикам быстро понять указанную вами проблему, которую необходимо пересмотреть, или предлагаемое вами решение проблемы, которое необходимо реализовать. Они отличаются от обычных аннотаций тем, что на них можно действовать. действиеFIXME: - 需要计算出来илиTODO: - 需要实现.

  • 18.5использовать// FIXME:аннотировать вопрос

    class Calculator extends Abacus {
      constructor() {
        super();
    
        // FIXME: shouldn't use a global here
        total = 0;
      }
    }
    

  • 18.6использовать// TODO:Решение деаннотированной проблемы

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

Whitespace

  • 19.1Tab с двумя пробелами.indent

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

  • 19.2Поставьте пробел перед фигурными скобками. эслинт: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',
    });
    

  • 19.3в операторе управления (if, whileд.) с пробелом перед скобками. В вызовах функций и определениях нет пробела между списком параметров и именем функции. эслинт:keyword-spacing

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

  • 19.4Разделяйте операторы пробелами. эслинт:space-infix-ops

    // bad
    const x=y+5;
    
    // good
    const x = y + 5;
    

  • 19.5Пустая строка в конце файла.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;↵
    

  • 19.6Используйте отступы при длинных цепочках методов (> 2). Начните с точки, чтобы подчеркнуть, что строка является вызовом метода, а не новой инструкцией. эслинт: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);
    

  • 19.7Пустая строка перед следующим оператором после блока кода.

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

  • 19.8Не заполняйте блоки пустыми строками. эслинт: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);
    }
    

  • 19.9Не добавляйте несколько пустых строк между кодами. эслинт:no-multiple-empty-lines

    // bad
    class Person {
      constructor(fullName, email, birthday) {
        this.fullName = fullName;
    
    
        this.email = email;
    
    
        this.setAge(birthday);
      }
    
    
      setAge(birthday) {
        const today = new Date();
    
    
        const age = this.getAge(today, birthday);
    
    
        this.age = age;
      }
    
    
      getAge(today, birthday) {
        // ..
      }
    }
    
    // good
    class Person {
      constructor(fullName, email, birthday) {
        this.fullName = fullName;
        this.email = email;
        this.setAge(birthday);
      }
    
      setAge(birthday) {
        const today = new Date();
        const age = getAge(today, birthday);
        this.age = age;
      }
    
      getAge(today, birthday) {
        // ..
      }
    }
    

  • 19.10Не добавляйте пробелы между скобками. эслинт: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);
    }
    

  • 19.11Не добавляйте пробелы между квадратными скобками. См. пример. эслинт:array-bracket-spacing

    // bad
    const foo = [ 1, 2, 3 ];
    console.log(foo[ 0 ]);
    
    // good, 逗号分隔符还是要空格的
    const foo = [1, 2, 3];
    console.log(foo[0]);
    

  • 19.12Добавьте пробелы между фигурными скобками. эслинт:object-curly-spacing

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

  • 19.13Избегайте строк кода длиннее 100 символов (включая пробелы).

  • Примечание: длявыше --strings--длина строки, длинные строки не подпадают под это правило и не должны разбиваться. эслинт:max-len

    Почему?Это обеспечивает удобочитаемость и ремонтопригодность

    // 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.'));
    

  • 19.14Также добавьте пробелы между фигурными скобками в качестве операторов --{после и}пробелы необходимы раньше. эслинт:block-spacing

    // bad
    function foo() {return true;}
    if (foo) { bar = 0;}
    
    // good
    function foo() { return true; }
    if (foo) { bar = 0; }
    

  • 19.15 ,без пробелов перед,,Пробел обязателен после. эслинт:comma-spacing

    // bad
    var foo = 1,bar = 2;
    var arr = [1 , 2];
    
    // good
    var foo = 1, bar = 2;
    var arr = [1, 2];
    

  • 19.16В вычисляемых свойствах требуются пробелы. Обратитесь к приведенным выше правилам для фигурных и квадратных скобок. эслинт:computed-property-spacing

    // bad
    obj[foo ]
    obj[ 'foo']
    var x = {[ b ]: a}
    obj[foo[ bar ]]
    
    // good
    obj[foo]
    obj['foo']
    var x = { [b]: a }
    obj[foo[bar]]
    

  • 19.17При вызове функции не используйте пробел между именем функции и круглыми скобками. эслинт:func-call-spacing

    // bad
    func ();
    
    func
    ();
    
    // good
    func();
    

  • 19.18В буквальном свойстве объектаkey valueМежду ними должны быть промежутки. эслинт:key-spacing

    // bad
    var obj = { "foo" : 42 };
    var obj2 = { "foo":42 };
    
    // good
    var obj = { "foo": 42 };
    

  • 19.20Избегайте нескольких пустых строк. В конце файла допускаются только пустые строки. эслинт:no-multiple-empty-lines

    // bad
    var x = 1;
    
    
    
    var y = 2;
    
    // good
    var x = 1;
    
    var y = 2;
    

Commas

  • 20.1Не ставьте перед запятыми. эслинт: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',
    };
    

  • 20.2Дополнительная запятая в конце:хочу eslint: comma-dangle

    Почему?Это приводит к более чистым различиям git. Кроме того, транспиляторы, такие как Babel, удаляют лишние запятые в транспилируемом коде, что означает, что вам не нужно беспокоиться об этом в старых браузерах.проблема с запятой.

    // bad - 没有结尾逗号的 git diff
    const hero = {
         firstName: 'Florence',
    -    lastName: 'Nightingale'
    +    lastName: 'Nightingale',
    +    inventorOf: ['coxcomb chart', 'modern nursing']
    };
    
    // good - 有结尾逗号的 git diff
    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
    )
    

Semicolons

  • 21.1 Yup. eslint: semi

    Почему? Когда JavaScript встречает строку, которая не заканчивается точкой с запятой, он выполняетАвтоматически вставлять точки с запятойAutomatic Semicolon InsertionЭто правило определяет, добавляется ли точка с запятой в конце строки. Если JavaScript по ошибке вставит точку с запятой в разрывы строк, может произойти странное поведение. По мере того, как в JavaScript добавляются новые функции, эти правила становятся более сложными и трудными для понимания. Явные операторы закрытия и настройка проверок кода, чтобы не отлавливать точки с запятой, могут помочь вам предотвратить эту ошибку.

    // bad
    (function () {
      const name = 'Skywalker'
      return name
    })()
    
    // good
    (function () {
      const name = 'Skywalker';
      return name;
    }());
    
    // good, 行首加分号,避免文件被连接到一起时立即执行函数被当做变量来执行。
    ;(() => {
      const name = 'Skywalker';
      return name;
    }());
    

    Read more.

Type Casting & Coercion

  • 22.1Выполнить приведение в начале высказывания.

  • 22.2 Strings: eslint: no-new-wrappers

    // => this.reviewScore = 9;
    
    // bad
    const totalScore = new String(this.reviewScore); // typeof totalScore is "object" not "string"
    
    // bad
    const totalScore = this.reviewScore + ''; // invokes this.reviewScore.valueOf()
    
    // bad
    const totalScore = this.reviewScore.toString(); // 不保证返回string
    
    // good
    const totalScore = String(this.reviewScore);
    

  • 22.3Номера: сNumberсделать преобразование типов,parseIntПреобразование строк часто требует системы счисления. эслинт: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Пожалуйста, объясните в комментариях, почему вы используете сменные операции и что вы делаете. какие бы дикие вещи вы ни делали, например, из-заparseIntЭто ваше узкое место в производительности, которое заставляет вас использовать сменные операции. Пожалуйста, объясните это, потому чтопричины производительности,

    // good
    /**
     * parseInt是代码运行慢的原因
     * 用Bitshifting将字符串转成数字使代码运行效率大幅增长
     */
    const val = inputValue >> 0;
    

  • 22.5 Уведомление:Будьте осторожны с операциями сдвига.64-битныйПредставлено, но операции сдвига часто возвращают 32 как целое числоsource). Операции сдвига могут привести к неожиданному поведению целых чисел размером более 32 бит.DiscussionНаибольшее 32-битное целое число равно 2 147 483 647:

    2147483647 >> 0 //=> 2147483647
    2147483648 >> 0 //=> -2147483648
    2147483649 >> 0 //=> -2147483647
    

  • 22.6логическое значение:

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

Naming Conventions

  • 23.1Избегайте имен, состоящих из одной буквы, и делайте имена описательными. эслинт:id-length

    // bad
    function q() {
      // ...
    }
    
    // good
    function query() {
      // ...
    }
    

  • 23.2Назовите свои объекты, функции и экземпляры в верблюжьем регистре. эслинт:camelcase

    // bad
    const OBJEcttsssss = {};
    const this_is_my_object = {};
    function c() {}
    
    // good
    const thisIsMyObject = {};
    function thisIsMyFunction() {}
    

  • 23.3Назовите классы в camelCase. эслинт:new-cap

    // bad
    function user(options) {
      this.name = options.name;
    }
    
    const bad = new user({
      name: 'nope',
    });
    
    // good
    class User {
      constructor(options) {
        this.name = options.name;
      }
    }
    
    const good = new User({
      name: 'yup',
    });
    

  • 23.4Не используйте начальные или конечные символы подчеркивания. эслинт:no-underscore-dangle

    Почему?В JavaScript нет понятия закрытых свойств или закрытых методов. Хотя начальное подчеркивание обычно концептуально означает «частное», на самом деле эти свойства полностью общедоступны, поэтому эта часть также является содержимым вашего API. Эта концепция может привести разработчиков к мысли, что ее изменение не приведет к сбою и не потребует тестирования. Если вы хотите, чтобы что-то было «личным», не делайте этого здесь.

    // bad
    this.__firstName__ = 'Panda';
    this.firstName_ = 'Panda';
    this._firstName = 'Panda';
    
    // good
    this.firstName = 'Panda';
    

  • 23.5не сохранять ссылкиthis, используя функцию стрелки илиПривязка функций — Function#bind.

    // bad
    function foo() {
      const self = this;
      return function () {
        console.log(self);
      };
    }
    
    // bad
    function foo() {
      const that = this;
      return function () {
        console.log(that);
      };
    }
    
    // good
    function foo() {
      return () => {
        console.log(this);
      };
    }
    

  • 23.6Экспорт по умолчанию экспортирует модуль A, тогда имя файла также называется A.*, а параметр при импорте также называется A. Случай точно такой же.

    // file 1 contents
    class CheckBox {
      // ...
    }
    export default CheckBox;
    
    // file 2 contents
    export default function fortyTwo() { return 42; }
    
    // file 3 contents
    export default function insideDirectory() {}
    
    // in some other file
    // bad
    import CheckBox from './checkBox'; // PascalCase import/export, camelCase filename
    import FortyTwo from './FortyTwo'; // PascalCase import/filename, camelCase export
    import InsideDirectory from './InsideDirectory'; // PascalCase import/filename, camelCase export
    
    // bad
    import CheckBox from './check_box'; // PascalCase import/export, snake_case filename
    import forty_two from './forty_two'; // snake_case import/filename, camelCase export
    import inside_directory from './inside_directory'; // snake_case import, camelCase export
    import index from './inside_directory/index'; // requiring the index file explicitly
    import insideDirectory from './insideDirectory/index'; // requiring the index file explicitly
    
    // good
    import CheckBox from './CheckBox'; // PascalCase export/import/filename
    import fortyTwo from './fortyTwo'; // camelCase export/import/filename
    import insideDirectory from './insideDirectory'; // camelCase export/import/directory name/implicit "index"
    // ^ supports both insideDirectory.js and insideDirectory/index.js
    

  • 23.7Когда ваш экспортный по умолчаю является функцией, имя функции соответствует небольшому верблюду, а имя файла должно соответствовать имени функции.

    function makeStyleGuide() {
      // ...
    }
    
    export default makeStyleGuide;
    

  • 23.8Используйте большой верблюжий регистр при экспорте структуры/класса/синглтона/библиотеки/объекта.

    const AirbnbStyleGuide = {
      es6: {
      }
    };
    
    export default AirbnbStyleGuide;
    

  • 23.9Аббревиатуры и аббревиатуры должны быть все в верхнем регистре или все в нижнем регистре.

    Почему?Имена читают люди, а не подстраиваются под компьютерные алгоритмы.

    // bad
    import SmsContainer from './containers/SmsContainer';
    
    // bad
    const HttpRequests = [
      // ...
    ];
    
    // good
    import SMSContainer from './containers/SMSContainer';
    
    // good
    const HTTPRequests = [
      // ...
    ];
    
    // also good
    const httpRequests = [
      // ...
    ];
    
    // best
    import TextMessageContainer from './containers/TextMessageContainer';
    
    // best
    const requests = [
      // ...
    ];
    

  • 23.10Вы можете установить статическую переменную с заглавными буквами, она должна соответствовать трем условиям.

    1. переменная экспорта
    2. даconstопределено, гарантированно не изменится
    3. Эта переменная является доверенной, и ее вложенные атрибуты не могут быть изменены.

    Зачем?Это дополнительный инструмент, который помогает разработчикам определить, является ли переменная неизменной.

    • для всехconstА переменные? - Это ненужно. Переменные в верхнем регистре не должны определяться и использоваться в одном и том же файле, они должны использоваться только как экспортируемые переменные. Согласен!
    • А что насчет экспортируемых объектов? - Переменные в верхнем регистре находятся на самом высоком уровне экспорта (например,EXPORTED_OBJECT.key) и все содержащиеся в нем подсвойства являются неизменяемыми.
    // bad
    const PRIVATE_VARIABLE = 'should not be unnecessarily uppercased within a file';
    
    // bad
    export const THING_TO_BE_CHANGED = 'should obviously not be uppercased';
    
    // bad
    export let REASSIGNABLE_VARIABLE = 'do not use let with uppercase variables';
    
    // ---
    
    // 允许但不够语义化
    export const apiKey = 'SOMEKEY';
    
    // 在大多数情况下更好
    export const API_KEY = 'SOMEKEY';
    
    // ---
    
    // bad - 不必要的大写键,没有增加任何语言
    export const MAPPING = {
      KEY: 'value'
    };
    
    // good
    export const MAPPING = {
      key: 'value'
    };
    

Accessors

  • 24.1Функции доступа для свойств не требуются.

  • 24.2Не используйте геттеры/сеттеры JavaScript, так как они имеют побочные эффекты и их сложно тестировать, поддерживать и понимать. Вместо этого вы можете использовать getVal() и setVal('hello') для создания собственных функций доступа.

    // bad
    class Dragon {
      get age() {
        // ...
      }
    
      set age(value) {
        // ...
      }
    }
    
    // good
    class Dragon {
      getAge() {
        // ...
      }
    
      setAge(value) {
        // ...
      }
    }
    

  • 24.3Если свойство/методboolean, использоватьisVal()илиhasVal()

    // bad
    if (!dragon.age()) {
      return false;
    }
    
    // good
    if (!dragon.hasAge()) {
      return false;
    }
    

  • 24.4Можно использовать функции get() и set(), но они должны использоваться вместе.

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

Events

  • 25.1При загрузке данных в событие (будь то событие DOM или многие свойства, такие как событие Backbone) с помощью хэша, а не необработанного значения. Это позволяет последующим участникам (программистам) загружать больше данных в событие без необходимости находить или обновлять каждый обработчик. Например:

    // bad
    $(this).trigger('listingUpdated', listing.id);
    
    // ...
    
    $(this).on('listingUpdated', (e, listingID) => {
      // do something with listingID
    });
    

    prefer:

    // good
    $(this).trigger('listingUpdated', { listingID: listing.id });
    
    // ...
    
    $(this).on('listingUpdated', (e, data) => {
      // do something with data.listingID
    });
    

jQuery

  • 26.1объект jQuery для$переменное представление.

    // bad
    const sidebar = $('.sidebar');
    
    // good
    const $sidebar = $('.sidebar');
    
    // good
    const $sidebarBtn = $('.sidebar-btn');
    

  • 26.2Постановка поиска jQuery

    // bad
    function setSidebar() {
      $('.sidebar').hide();
    
      // ...
    
      $('.sidebar').css({
        'background-color': 'pink'
      });
    }
    
    // good
    function setSidebar() {
      const $sidebar = $('.sidebar');
      $sidebar.hide();
    
      // ...
    
      $sidebar.css({
        'background-color': 'pink'
      });
    }
    

  • 26.3Каскад для поиска DOM$('.sidebar ul')или Родительский узел > Дочерний узел$('.sidebar > ul'). jsPerf

  • 26.4Область запроса с объектом jQueryfindзапрос метода

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

Совместимость с ES5

ECMAScript 6+ (ES 2015+) Styles

  • 28.1Вот ссылка на различные собранные функции ES6
  1. Стрелочные функции - Стрелочные функции
  2. Классы - Классы
  3. Сокращение объекта - Сокращение объекта
  4. Сокращение объекта - Object Concise
  5. Вычисляемые свойства объекта - Вычисляемые свойства объекта
  6. Строки шаблона - Строки шаблона
  7. Присвоение деструктуризации - Деструктуризация
  8. Параметры по умолчанию - Параметры по умолчанию
  9. Rest
  10. Array Spreads
  11. Let and Const
  12. Оператор возведения в степень - Оператор возведения в степень
  13. Итераторы и генераторы - Итераторы и генераторы
  14. Модули - Модули

  • 28.2Не используйте егоTC39 proposals, TC39 еще не достиг стадии 3.

    Why? это не финальная версия, у него еще может быть много изменений, или он может быть отозван. Мы хотим использовать JavaScript, предложение еще не JavaScript.

Standard Library

стандартная библиотекаСодержит некоторые классы инструментов, функции которых повреждены, но оставлены по историческим причинам.

  • 29.1использоватьNumber.isNaNвместо глобальногоisNaN. eslint: no-restricted-globals

    Почему?isNaNприводить нечисловые к числовым, то для любого приведения кNaNпеременные возвращаютсяtrueЕсли вы хотите использовать эту функцию, используйте ее явно.

    // 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использоватьNumber.isFiniteзаменятьisFinite. eslint: no-restricted-globals

    Почему? Причина та же, что и выше. Он преобразует нечисловую переменную в число, а затем выносит суждение.

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

Testing

  • 30.1 Yup.

    function foo() {
      return true;
    }
    

  • 30.2 No, but seriously:
  • Независимо от того, какой тестовый фреймворк вы используете, вам необходимо писать тесты.
  • Попробуйте написать много маленьких и красивых чистых функций, чтобы уменьшить количество мутаций.
  • Будьте осторожны с заглушками и макетами — это может сделать ваши тесты хрупкими.
  • Предпочтительно на Airbnbmocha.tapeИногда используется для тестирования небольших независимых модулей.
  • 100% тестовое покрытие — это то, к чему мы стремимся, даже если на практике это редко достигается.
  • Всякий раз, когда вы исправляете ошибку, напишите регрессионный тест. Ошибка исправлена, регрессионного тестирования нет, есть вероятность, что проблема снова сломается в будущем.