предисловие
Эта статья основана на проекте github.airbnb/javascriptПеревод, также добавил некоторое личное понимание. Спецификации помогают нам улучшить читаемость кода и избежать ненужных ошибок. Однако единых стандартов и жестких требований нет, вот лишь несколько рекомендаций для всех, а лучший тот, который подходит команде и вам самим.
Адрес личного блога🍹🍰 fe-код
тип
- 1.1 Основные типы
При назначении примитивного типа значение типа должно использоваться напрямую
string
number
boolean
null
undefined
symbol
const foo = 1;
let bar = foo;
bar = 9;
console.log(foo, bar); // => 1,9
- сложный тип
Назначение сложного типа на самом деле является ссылкой на адрес
object
array
function
const foo = [1, 2];
const bar = foo;
bar[0] = 9;
console.log(foo[0], bar[0]); // => 9, 9
// const 只能阻止引用类型地址的重新赋值
// 并不能保证引用类型的属性等不变
Использование статуса (первоначально в справочнике)
- 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
объект
- 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 Сокращение метода.
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
. При деструктуризации присваивания для получения нескольких свойств, заданных объектом, рекомендуется использовать оператор rest, который также...
.
// very bad
const original = { a: 1, b: 2 };
const copy = Object.assign(original, { c: 3 });
delete copy.a; // so does this 改变了 original
// bad
const original = { a: 1, b: 2 };
const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 }
// good
const original = { a: 1, b: 2 };
const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }
const { a, ...noA } = copy; // noA => { b: 2, c: 3 }
множество
- 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,
];
разрушать
- 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) {
return { left, right, top, bottom };
}
const { left, top } = processInput(input);
нить
- 6.1 Строка объединена одинарными кавычками
''
. эслинт:quotes
// bad
const name = "Capt. Janeway";
// bad - 模板应该包含插入文字或换行
const name = `Capt. Janeway`;
// good
const name = 'Capt. Janeway';
- 6.2 Не следует использовать
+
Объединить строки новой строки.
Неудобный в использовании и плохо читаемый
// 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}'`;
функция
- 7.1 Используйте именованные функциональные выражения вместо объявлений функций. эслинт:
func-style
Объем объявления функции увеличивается, что снижает читабельность и удобство сопровождения кода. Если вы найдете функцию, которая настолько велика и сложна, что мешает пониманию остальной части файла, возможно, пришло время выделить функцию в отдельный модуль. (Discussion)
// bad
function foo() {
// ...
}
// bad
const foo = function () {
// ...
};
// good
const short = function longUniqueMoreDescriptiveLexicalFoo() {
// ...
};
- 7.2 Заключите непосредственную функцию в круглые скобки. эслинт:
wrap-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 Уведомление:В 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
...
Уточните, какие параметры вы хотите использовать.
// bad
function concatenateAll() {
const args = Array.prototype.slice.call(arguments);
return args.join('');
}
// good
function concatenateAll(...args) {
return args.join('');
}
- 7.8 Используйте синтаксис параметров по умолчанию вместо переназначения параметров в функциях.
// really bad
function handleThings(opts) {
// 虽然你想这么写, 但是这个会带来一些细微的bug
// 如果 opts 的值为 false, 它会被赋值为 {}
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
// 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
// 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 Использование
...
. эслинт: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,
);
стрелочная функция
- 8.1 Если вы хотите использовать анонимные функции в качестве обратных вызовов, лучше использовать стрелочные функции eslint:
prefer-arrow-callback
,arrow-spacing
Он создает функцию, которая выполняется в контексте, что обычно и требуется, и имеет более краткий синтаксис.
// 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
}));
// 表达式有副作用就不要用隐式返回
function foo(callback) {
const val = callback();
if (val === true) {
// Do something if callback returns true
}
}
let bool = false;
// bad
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 Для ясности и согласованности всегда заключайте аргументы в скобки 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 Применяйте ограничение, согласно которому тело функции находится за стрелкой при использовании неявного возврата. эслинт:
implicit-arrow-linebreak
// bad
(foo) =>
bar;
(foo) =>
(bar);
// good
(foo) => bar;
(foo) => (bar);
(foo) => (
bar
)
Классы и конструкторы
- 9.1 Всегда используйте
class
, чтобы избежать прямого манипулированияprototype
// 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; }
}
модуль
- 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 Не используйте подстановочные знаки import *
// 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 Запись импортируется только один раз.
эслинт:
no-duplicate-imports
Почему? Импорт нескольких строк из одного и того же пути усложняет поддержку кода.
// 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 Не экспортируйте изменяемые привязки
эслинт:
import/no-mutable-exports
Минимизируйте состояние и обеспечьте неизменность данных. Хотя этот метод может потребоваться в некоторых сценариях, в общем случае следует экспортировать константы.
// bad
let foo = 3;
export { foo }
// good
const foo = 3;
export { foo }
- 10.6 В модуле только с одним экспортом используйте
export default
лучше. эслинт:import/prefer-default-export
Для большего количества файлов рекомендуется делать только одну вещь для каждого файла и экспортировать, что более читабельно и удобно в сопровождении.
// bad
export function foo() {}
// good
export default function foo() {}
- 10.7
import
перед всеми другими заявлениями. эслинт:import/first
Предотвращайте неожиданное поведение.
// 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';
- 10.9 Синтаксис загрузчика Webpack не разрешен в операторах импорта
эслинт:
import/no-webpack-loader-syntax
предпочтительно в
webpack.config.js
написать в
// bad
import fooSass from 'css!sass!foo.scss';
import barCss from 'style!css!bar.css';
// good
import fooSass from 'foo.scss';
import barCss from 'bar.css';
итераторы и генераторы
- 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 Не используйте генераторы сейчас
плохая совместимость
- 11.3 Если вы должны использовать его, или если вы игнорируете егонаше предложение, убедитесь, что пробелы между их сигнатурами функций указаны правильно. эслинт:
generator-star-spacing
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* () {
// ...
}
Атрибуты
- 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;
Переменная
- 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 Объявления переменных в разумных местах
// 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++ или вместо операторов для изменения ваших значений. Отключение операторов унарного увеличения и уменьшения также предотвращает непреднамеренное предварительное увеличение/уменьшение значений, уменьшая непредвиденное поведение программы.
// bad
let 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
let 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' 对象
продвигать
- 14.1 Объявления var подняты. объявлениям const и let дается так называемая новая концепцияTemporal Dead Zones (TDZ). Важно знать, почемуtypeof больше не безопасен.
function example() {
console.log(notDefined); // => throws a ReferenceError
}
// 在变量声明之前使用会正常输出,是因为变量声明提升,值没有。
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.
сравнить и приравнять
-
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.4
switch case
в, вcase
иdefault
Используйте фигурные скобки, чтобы создать блок в предложении (например:let
,const
,function
, andclass
). eslint rules:no-case-declarations
.
Лексические объявления видны во всем блоке переключателей, но инициализируются только при назначении, что происходит только при достижении регистра. Проблемы возникают, когда несколько предложений 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.5 Тернарные выражения не должны быть вложенными и обычно представляют собой однострочные выражения.
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
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;
кусок
- 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
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
, тогда ты можешьelse 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;
}
}
контроль
- 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();
}
Примечания
- 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`, который помогает другим разработчикам быстро понять указанную вами проблему или предложенное вами решение проблемы.
class Calculator extends Abacus {
constructor() {
super();
// FIXME: shouldn't use a global here
total = 0;
}
}
class Calculator extends Abacus {
constructor() {
super();
// TODO: total should be configurable by an options param
this.total = 0;
}
}
космос
- 19.1 Вкладка Используйте два пробела (или четыре, если вам нравится, но единство команды обязательно). эслинт:
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
Пробел перед скобками etc. В вызовах функций и определениях между именем функции и круглыми скобками нет пробела. эслинт: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 Перенос при наличии длинной цепочки методов (обычно более двух). Начните с точки, чтобы подчеркнуть, что строка является вызовом метода, а не новой инструкцией. эслинт:
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 Не добавляйте пробелы между круглыми скобками. эслинт:
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.10 Без пробелов между квадратными скобками. См. пример. эслинт:
array-bracket-spacing
// bad
const foo = [ 1, 2, 3 ];
console.log(foo[ 0 ]);
// good, 逗号后面要加空格
const foo = [1, 2, 3];
console.log(foo[0]);
- 19.11 Фигурные скобки
{}
Рижские просторы. эслинт:object-curly-spacing
// bad
const foo = {clark: 'kent'};
// good
const foo = { clark: 'kent' };
// bad
function foo() {return true;}
if (foo) { bar = 0;}
// good
function foo() { return true; }
if (foo) { bar = 0; }
- 19.12 Избегайте строк кода длиннее 100 символов (включая пробелы, простые строки не переносятся).
// 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.13
,
избегайте пробелов перед,,
Пробел обязателен после. эслинт:comma-spacing
// bad
var foo = 1,bar = 2;
var arr = [1 , 2];
// good
var foo = 1, bar = 2;
var arr = [1, 2];
- 19.14 В свойствах объекта между ключами и значениями должны быть пробелы. эслинт:
key-spacing
// bad
var obj = { "foo" : 42 };
var obj2 = { "foo":42 };
// good
var obj = { "foo": 42 };
-
19.15 Без пробелов в конце строки. эслинт:
no-trailing-spaces
-
19.16 Избегайте нескольких пустых строк. В конце файла допускаются только пустые строки. эслинт:
no-multiple-empty-lines
// bad
var x = 1;
var y = 2;
// good
var x = 1;
var y = 2;
запятая
- 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
// 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
)
точка с запятой
- 21.1 Когда JavaScript встречает новую строку без точки с запятой, он использует
Automatic Semicolon Insertion
Это правило определяет, добавляется ли точка с запятой в конце строки. Тем не менее, ASI имеет некоторые причудливые особенности поведения, и если JavaScript неправильно интерпретирует символы новой строки, ваш код сломается. Таким образом, использование точки с запятой явно уменьшает эту неопределенность.
// bad
(function () {
const name = 'Skywalker'
return name
})()
// good
(function () {
const name = 'Skywalker';
return name;
}());
// good
;(() => {
const name = 'Skywalker';
return name;
}());
тип
-
22.1 Выполнить приведение в начале объявления.
-
22.2 String 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 eslint:
radix
const inputValue = '4';
// bad
const val = new Number(inputValue);
// bad
const val = +inputValue;
// bad
const val = inputValue >> 0;
// bad
const val = parseInt(inputValue);
// good
const val = Number(inputValue);
// good
const val = parseInt(inputValue, 10);
- 22.4 Объясните, пожалуйста, в комментариях, почему используется операция сдвига, независимо от того, что вы делаете, например, из-за
parseInt
Это ваше узкое место в производительности, которое заставляет вас использовать сменные операции. Пожалуйста, объясните это, потому чтопричины производительности,
// good
/**
* parseInt 导致代码运行慢
* Bitshifting the String 将其强制转换为数字使其快得多。
*/
const val = inputValue >> 0;
- 22.5 Уведомление:Будьте осторожны при использовании операций битового сдвига. Числа представлены в виде 64-битных значений, но операции сдвига битов всегда возвращают 32-битные целые числа. Битовый сдвиг может вызвать неожиданное поведение для целочисленных значений, превышающих 32 бита.
2147483647 >> 0 //=> 2147483647
2147483648 >> 0 //=> -2147483648
2147483649 >> 0 //=> -2147483647
- 22.6 Booleans
const age = 0;
// bad
const hasAge = new Boolean(age);
// good
const hasAge = Boolean(age);
// best
const hasAge = !!age;
соглашение об именовании
- 23.1 Избегайте использования однобуквенных имен, чтобы сделать ваши имена более семантическими. эслинт:
id-length
// bad
function q() {
// ...
}
// good
function query() {
// ...
}
- 23.2 Назовите свои объекты, функции и экземпляры с помощью camelCase. эслинт:
camelcase
// bad
const OBJEcttsssss = {};
const this_is_my_object = {};
function c() {}
// good
const thisIsMyObject = {};
function thisIsMyFunction() {}
- 23.3 Назовите классы с помощью PascalCase. эслинт:
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
ссылка, используя функции стрелок или жесткую привязку.
// 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 Имя файла должно совпадать с именем файла экспорта по умолчанию (
export default
) точно соответствует названию
// 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 Экспорт по умолчанию (
export default
) для одной функции имя функции и имя файла совпадают.
function makeStyleGuide() {
// ...
}
export default makeStyleGuide;
- 23.8 Используйте PascalCase при экспорте объекта конструктора/класса/одиночки/библиотеки.
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 = [
// ...
];
// best
import TextMessageContainer from './containers/TextMessageContainer';
// best
const Requests = [
// ...
];
- 23.10 Все заглавные буквы определяют константы для экспорта
// 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';
// ---
// allowed but does not supply semantic value
export const apiKey = 'SOMEKEY';
// better in most cases
export const API_KEY = 'SOMEKEY';
// ---
// bad - unnecessarily uppercases key while adding no semantic value
export const MAPPING = {
KEY: 'value'
};
// good
export const MAPPING = {
key: 'value'
};
аксессуар
-
24.1 Функции доступа для свойств не требуются.
-
24.2 Не используйте геттеры/сеттеры JavaScript, потому что они имеют побочные эффекты и их сложно тестировать, поддерживать и понимать. При необходимости вы можете использовать getVal() и setVal() для построения.
// 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 При передаче данных событиям или другим не используйте примитивные значения напрямую, а оборачивайте их в объекты. Таким образом, параметры необходимо увеличивать или уменьшать в будущем, не находя каждый используемый процессор.
// 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
});
резюме
Так называемая спецификация больше для читабельности кода, ведь наш код важнее, чтобы его видели люди. В то же время разумные спецификации также помогут нам избежать многих ненужных ошибок.
группа обмена
Обратите внимание на публичный аккаунт WeChat: внешний движок, ответ: добавить группу.
постскриптум
Если вы это видите, и эта статья вам полезна, надеюсь, вы сможете поддержать автора своими ручонками, спасибо 🍻. Если в тексте что-то не так, укажите на это и поделитесь. Хорошо, я снова потратил впустую время всех, спасибо за чтение, увидимся в следующий раз!
- Репозиторий статей 🍹🍰fe-код
- Система социального чата (vue + node + mongodb) — 💘🍦🙈Vchat
Заинтересованные студенты могут обратить внимание на мой публичный номерпередний двигатель, весело и познавательно.