Руководство по стилю JavaScript для Airbnb() {
В основном разумный подход к JavaScript
Уведомление: В этом руководстве предполагается, что вы используетеBabel, и требует, чтобы вы использовали или эквивалентноbabel-preset-airbnb. Также предположим, что вы установили в своем приложении или эквивалентныйairbnb-browser-shimsиз
shims/polyfills
содержание
- Types
- References
- Objects
- Arrays
- Destructuring
- Strings
- Functions
- Arrow Functions
- Classes & Constructors
- Modules
- Iterators and Generators
- Properties
- Variables
- Hoisting
- Comparison Operators & Equality
- Blocks
- Control Statements
- Comments
- Whitespace
- Commas
- Semicolons
- Type Casting & Coercion
- Naming Conventions
- Accessors
- Events
- jQuery
- ECMAScript 5 Compatibility
- ECMAScript 6+ (ES 2015+) Styles
- Standard Library
- Testing
- Performance
- Resources
- In the Wild
- Translation
- The JavaScript Style Guide Guide
- Chat With Us About JavaScript
- Contributors
- License
- 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.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Не используйте итераторы. Вместо этого используйте расширенные функции JavaScript
for-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.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.4Для получения дополнительной информации см. Ангуса Кролла.Истина, Равенство и JavaScript - Равенство Истины и JavaScript
-
15.5существует
case
а такжеdefault
Используйте фигурные скобки в предложении, чтобы создать область, содержащую объявления синтаксиса (например,let
,const
,function
, andclass
). 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.19Без пробелов в конце строки. эслинт:
no-trailing-spaces
-
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
-
Почему? Когда 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; }());
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Вы можете установить статическую переменную с заглавными буквами, она должна соответствовать трем условиям.
- переменная экспорта
- да
const
определено, гарантированно не изменится - Эта переменная является доверенной, и ее вложенные атрибуты не могут быть изменены.
Зачем?Это дополнительный инструмент, который помогает разработчикам определить, является ли переменная неизменной.
- для всех
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Область запроса с объектом jQuery
find
запрос метода// bad $('ul', '.sidebar').hide(); // bad $('.sidebar').find('ul').hide(); // good $('.sidebar ul').hide(); // good $('.sidebar > ul').hide(); // good $sidebar.find('ul').hide();
Совместимость с ES5
- 27.1Ссылаться наKangaxES5Список совместимости.
ECMAScript 6+ (ES 2015+) Styles
- 28.1Вот ссылка на различные собранные функции ES6
- Стрелочные функции - Стрелочные функции
- Классы - Классы
- Сокращение объекта - Сокращение объекта
- Сокращение объекта - Object Concise
- Вычисляемые свойства объекта - Вычисляемые свойства объекта
- Строки шаблона - Строки шаблона
- Присвоение деструктуризации - Деструктуризация
- Параметры по умолчанию - Параметры по умолчанию
- Rest
- Array Spreads
- Let and Const
- Оператор возведения в степень - Оператор возведения в степень
- Итераторы и генераторы - Итераторы и генераторы
- Модули - Модули
-
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:
- Независимо от того, какой тестовый фреймворк вы используете, вам необходимо писать тесты.
- Попробуйте написать много маленьких и красивых чистых функций, чтобы уменьшить количество мутаций.
- Будьте осторожны с заглушками и макетами — это может сделать ваши тесты хрупкими.
- Предпочтительно на Airbnb
mocha
.tape
Иногда используется для тестирования небольших независимых модулей. - 100% тестовое покрытие — это то, к чему мы стремимся, даже если на практике это редко достигается.
- Всякий раз, когда вы исправляете ошибку, напишите регрессионный тест. Ошибка исправлена, регрессионного тестирования нет, есть вероятность, что проблема снова сломается в будущем.