- Notifications
You must be signed in to change notification settings - Fork270
Перевод «JavaScript Style Guide» от Airbnb
leonidlebedev/javascript-airbnb
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
Руководство по написанию JavaScript-кода отAirbnb() {
Наиболее разумный подход к написанию JavaScript-кода
Замечание: это руководство подразумевает использованиеBabel вместе сbabel-preset-airbnb или аналогом. Оно также предполагает установленный shims/polyfills в вашем приложении, такой какairbnb-browser-shims или аналог.
Это руководство также доступно на других языках. СмотритеПереводы.
Другие руководства
- Типы
- Объявление переменных
- Объекты
- Массивы
- Деструктуризация
- Строки
- Функции
- Стрелочные функции
- Классы и конструкторы
- Модули
- Итераторы и генераторы
- Свойства
- Переменные
- Подъём
- Операторы сравнения и равенства
- Блоки
- Управляющие операторы
- Комментарии
- Пробелы
- Запятые
- Точка с запятой
- Приведение типов
- Соглашение об именовании
- Аксессоры
- События
- jQuery
- Поддержка ECMAScript 5
- Возможности ECMAScript 6+ (ES 2015+)
- Стандартная библиотека
- Тестирование
- Производительность
- Ресурсы
- В реальной жизни
- Переводы
- Пообщаться с разработчиками Airbnb
- Участники перевода
- Лицензия
- Поправки
1.1Простые типы: Когда вы взаимодействуете с простым типом, вы напрямую работаете с его значением.
stringnumberbooleannullundefinedsymbolbigint
constfoo=1;letbar=foo;bar=9;console.log(foo,bar);// => 1, 9
- Symbol и BigInt не могут быть полностью заполифиллены, поэтому они не должны использоваться, если разработка ведётся для браузеров или других сред, которые не поддерживают их нативно.
1.2Сложные типы: Когда вы взаимодействуете со сложным типом, вы работаете со ссылкой на его значение.
objectarrayfunction
constfoo=[1,2];constbar=foo;bar[0]=9;console.log(foo[0],bar[0]);// => 9, 9
2.1 Используйте
constдля объявления переменных; избегайтеvar. eslint:prefer-const,no-const-assignПочему? Это гарантирует, что вы не сможете переопределять значения, т.к. это может привести к ошибкам и к усложнению понимания кода.
// плохоvara=1;varb=2;// хорошоconsta=1;constb=2;
2.2 Если вам необходимо переопределять значения, то используйте
letвместоvar. eslint:no-varПочему? Область видимости
let— блок, уvar— функция.// плохоvarcount=1;if(true){count+=1;}// хорошо, используйте let.letcount=1;if(true){count+=1;}
2.3 Помните, что у
letиconstблочная область видимости, в то время какvarимеет функциональную область видимости.// const и let существуют только в том блоке, в котором они определены.{leta=1;constb=1;varc=1;}console.log(a);// ReferenceErrorconsole.log(b);// ReferenceErrorconsole.log(c);// 1
В приведённом выше коде вы можете видеть, что ссылки на
aиbприведут к ошибкеReferenceError, в то время какcсодержит число. Это связано с тем, чтоaиbимеют блочную область видимости, в то время как уcфункциональная.
3.1 Для создания объекта используйте литеральную нотацию. eslint:
no-new-object// плохоconstitem=newObject();// хорошоconstitem={};
3.2 Используйте вычисляемые имена свойств, когда создаёте объекты с динамическими именами свойств.
Почему? Они позволяют вам определить все свойства объекта в одном месте.
functiongetKey(k){return`a key named${k}`;}// плохоconstobj={id:5,name:'San Francisco',};obj[getKey('enabled')]=true;// хорошоconstobj={id:5,name:'San Francisco',[getKey('enabled')]:true,};
3.3 Используйте сокращённую запись метода объекта. eslint:
object-shorthand// плохоconstatom={value:1,addValue:function(value){returnatom.value+value;},};// хорошоconstatom={value:1,addValue(value){returnatom.value+value;},};
3.4 Используйте сокращённую запись свойств объекта. eslint:
object-shorthandПочему? Это короче и понятнее.
constlukeSkywalker='Luke Skywalker';// плохоconstobj={lukeSkywalker:lukeSkywalker,};// хорошоconstobj={ lukeSkywalker,};
3.5 Группируйте ваши сокращённые записи свойств в начале объявления объекта.
Почему? Так легче сказать, какие свойства используют сокращённую запись.
constanakinSkywalker='Anakin Skywalker';constlukeSkywalker='Luke Skywalker';// плохоconstobj={episodeOne:1,twoJediWalkIntoACantina:2, lukeSkywalker,episodeThree:3,mayTheFourth:4, anakinSkywalker,};// хорошоconstobj={ lukeSkywalker, anakinSkywalker,episodeOne:1,twoJediWalkIntoACantina:2,episodeThree:3,mayTheFourth:4,};
3.6 Только недопустимые идентификаторы помещаются в кавычки. eslint:
quote-propsПочему? На наш взгляд, такой код легче читать. Это улучшает подсветку синтаксиса, а также облегчает оптимизацию для многих JS-движков.
// плохоconstbad={'foo':3,'bar':4,'data-blah':5,};// хорошоconstgood={foo:3,bar:4,'data-blah':5,};
3.7 Не вызывайте напрямую методы
Object.prototype, такие какhasOwnProperty,propertyIsEnumerable, иisPrototypeOf. eslint:no-prototype-builtinsПочему? Эти методы могут быть переопределены в свойствах объекта, который мы проверяем
{ hasOwnProperty: false }, или этот объект может бытьnull(Object.create(null)).// плохоconsole.log(object.hasOwnProperty(key));// хорошоconsole.log(Object.prototype.hasOwnProperty.call(object,key));// отличноconsthas=Object.prototype.hasOwnProperty;// Кэшируем запрос в рамках модуля.console.log(has.call(object,key));/* или */importhasfrom'has';// https://www.npmjs.com/package/hasconsole.log(has(object,key));
3.8 Используйте синтаксис расширения вместо
Object.assignдля поверхностного копирования объектов. Используйте параметр оставшихся свойств, чтобы получить новый объект с некоторыми опущенными свойствами. eslint:prefer-object-spread// очень плохоconstoriginal={a:1,b:2};constcopy=Object.assign(original,{c:3});// эта переменная изменяет `original` ಠ_ಠdeletecopy.a;// если сделать так// плохоconstoriginal={a:1,b:2};constcopy=Object.assign({},original,{c:3});// copy => { a: 1, b: 2, c: 3 }// хорошоconstoriginal={a:1,b:2};constcopy={ ...original,c:3};// copy => { a: 1, b: 2, c: 3 }const{ a, ...noA}=copy;// noA => { b: 2, c: 3 }
4.1 Для создания массива используйте литеральную нотацию. eslint:
no-array-constructor// плохоconstitems=newArray();// хорошоconstitems=[];
4.2 Для добавления элемента в массив используйтеArray#push вместо прямого присваивания.
constsomeStack=[];// плохоsomeStack[someStack.length]='abracadabra';// хорошоsomeStack.push('abracadabra');
4.3 Для копирования массивов используйте оператор расширения
....// плохоconstlen=items.length;constitemsCopy=[];leti;for(i=0;i<len;i+=1){itemsCopy[i]=items[i];}// хорошоconstitemsCopy=[...items];
4.4 Для преобразования итерируемого объекта в массив используйте оператор расширения
...вместоArray.from.constfoo=document.querySelectorAll('.foo');// хорошоconstnodes=Array.from(foo);// отличноconstnodes=[...foo];
4.5 Используйте
Array.fromдля преобразования массивоподобного объекта в массив.constarrLike={0:'foo',1:'bar',2:'baz',length:3};// плохоconstarr=Array.prototype.slice.call(arrLike);// хорошоconstarr=Array.from(arrLike);
4.6 Используйте
Array.fromвместо оператора расширения...для маппинга итерируемых объектов, это позволяет избежать создания промежуточного массива.// плохоconstbaz=[...foo].map(bar);// хорошоconstbaz=Array.from(foo,bar);
4.7 Используйте операторы
returnвнутри функций обратного вызова в методах массива. Можно опуститьreturn, когда тело функции состоит из одной инструкции, возвращающей выражение без побочных эффектов.8.2. eslint:array-callback-return// хорошо[1,2,3].map((x)=>{consty=x+1;returnx*y;});// хорошо[1,2,3].map((x)=>x+1);// плохо - нет возвращаемого значения, следовательно, `acc` становится `undefined` после первой итерации[[0,1],[2,3],[4,5]].reduce((acc,item,index)=>{constflatten=acc.concat(item);});// хорошо[[0,1],[2,3],[4,5]].reduce((acc,item,index)=>{constflatten=acc.concat(item);returnflatten;});// плохоinbox.filter((msg)=>{const{ subject, author}=msg;if(subject==='Mockingbird'){returnauthor==='Harper Lee';}else{returnfalse;}});// хорошоinbox.filter((msg)=>{const{ subject, author}=msg;if(subject==='Mockingbird'){returnauthor==='Harper Lee';}returnfalse;});
4.8 Если массив располагается на нескольких строках, то используйте разрывы строк после открытия и перед закрытием скобок.
// плохоconstarr=[[0,1],[2,3],[4,5],];constobjectInArray=[{id:1,},{id:2,}];constnumberInArray=[1,2,];// хорошоconstarr=[[0,1],[2,3],[4,5]];constobjectInArray=[{id:1,},{id:2,},];constnumberInArray=[1,2,];
5.1 При обращении к нескольким свойствам объекта используйте деструктуризацию объекта. eslint:
prefer-destructuringПочему? Деструктуризация сохраняет вас от создания временных переменных для этих свойств и от повторного доступа к объекту. Повторный доступ к объектам создаёт более повторяющийся код, требует большего чтения и создаёт больше возможностей для ошибок. Деструктуризация объектов также обеспечивает единое местоположение определения структуры объекта, которое используется в блоке, вместо того, чтобы требовать чтения всего блока для определения того, что используется.
// плохоfunctiongetFullName(user){constfirstName=user.firstName;constlastName=user.lastName;return`${firstName}${lastName}`;}// хорошоfunctiongetFullName(user){const{ firstName, lastName}=user;return`${firstName}${lastName}`;}// отличноfunctiongetFullName({ firstName, lastName}){return`${firstName}${lastName}`;}
5.2 Используйте деструктуризацию массивов. eslint:
prefer-destructuringconstarr=[1,2,3,4];// плохоconstfirst=arr[0];constsecond=arr[1];// хорошоconst[first,second]=arr;
5.3 Используйте деструктуризацию объекта для множества возвращаемых значений, но не делайте тоже самое с массивами.
Почему? Вы сможете добавить новые свойства через некоторое время или изменить порядок без последствий.
// плохоfunctionprocessInput(input){// затем происходит чудоreturn[left,right,top,bottom];}// при вызове нужно подумать о порядке возвращаемых данныхconst[left,__,top]=processInput(input);// хорошоfunctionprocessInput(input){// затем происходит чудоreturn{ left, right, top, bottom};}// при вызове выбираем только необходимые данныеconst{ left, top}=processInput(input);
6.1 Используйте одинарные кавычки
''для строк. eslint:quotes// плохоconstname="Capt. Janeway";// плохо - литерал шаблонной строки должен содержать интерполяцию или переводы строкconstname=`Capt. Janeway`;// хорошоconstname='Capt. Janeway';
6.2 Строки, у которых в строчке содержится более 100 символов, не пишутся на нескольких строчках с использованием конкатенации.
Почему? Работать с разбитыми строками неудобно и это затрудняет поиск по коду.
// плохоconsterrorMessage='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.';// плохоconsterrorMessage='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.';// хорошоconsterrorMessage='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 При создании строки программным путём используйте шаблонные строки вместо конкатенации. eslint:
prefer-templatetemplate-curly-spacingПочему? Шаблонные строки дают вам читабельность, лаконичный синтаксис с правильными символами перевода строк и функции интерполяции строки.
// плохоfunctionsayHi(name){return'How are you, '+name+'?';}// плохоfunctionsayHi(name){return['How are you, ',name,'?'].join();}// плохоfunctionsayHi(name){return`How are you,${name}?`;}// хорошоfunctionsayHi(name){return`How are you,${name}?`;}
6.5 Не используйте в строках необязательные экранирующие символы. eslint:
no-useless-escapeПочему? Обратные слеши ухудшают читабельность, поэтому они должны быть только при необходимости.
// плохоconstfoo='\'this\' \i\s \"quoted\"';// хорошоconstfoo='\'this\' is "quoted"';constfoo=`my name is '${name}'`;
7.1 Используйте функциональные выражения вместо объявлений функций. eslint:
func-styleПочему? У объявлений функций есть подъём. Это означает, что можно использовать функцию до того, как она определена в файле, но это вредит читабельности и поддержке. Если вы обнаружили, что определение функции настолько большое или сложное, что мешает понимать остальную часть файла, то, возможно, пришло время извлечь его в отдельный модуль. Не забудьте явно назвать функциональное выражение, независимо от того, подразумевается ли имя из содержащейся переменной (такое часто бывает в современных браузерах или при использовании компиляторов, таких как Babel). Это помогает точнее определять место ошибки по стеку вызовов. (Обсуждение)
// плохоfunctionfoo(){// ...}// плохоconstfoo=function(){// ...};// хорошо// лексическое имя, отличное от вызываемой(-ых) переменной(-ых)constfoo=functionuniqueMoreDescriptiveLexicalFoo(){// ...};
7.2 Оборачивайте в скобки немедленно вызываемые функции. eslint:
wrap-iifeПочему? Немедленно вызываемая функция представляет собой единый блок. Чтобы чётко показать это — оберните функцию и вызывающие скобки в ещё одни скобки. Обратите внимание, что в мире с модулями вам больше не нужны немедленно вызываемые функции.
// Немедленно вызываемая функция(function(){console.log('Welcome to the Internet. Please follow me.');}());
- 7.3 Никогда не объявляйте функции в нефункциональном блоке (
if,while, и т.д.). Вместо этого присвойте функцию переменной. Браузеры позволяют выполнить ваш код, но все они интерпретируют его по-разному. eslint:no-loop-func
7.4Примечание: ECMA-262 определяет
блоккак список инструкций. Объявление функции не является инструкцией.// плохоif(currentUser){functiontest(){console.log('Nope.');}}// хорошоlettest;if(currentUser){test=()=>{console.log('Yup.');};}
7.5 Никогда не называйте параметр
arguments. Он будет иметь приоритет над объектомarguments, который доступен для каждой функции.// плохоfunctionfoo(name,options,arguments){// ...}// хорошоfunctionfoo(name,options,args){// ...}
7.6 Никогда не используйте
arguments, вместо этого используйте синтаксис оставшихся параметров.... eslint:prefer-rest-paramsПочему?
...явно говорит о том, какие именно аргументы вы хотите извлечь. Кроме того, такой синтаксис создаёт настоящий массив, а не массивоподобный объект какarguments.// плохоfunctionconcatenateAll(){constargs=Array.prototype.slice.call(arguments);returnargs.join('');}// хорошоfunctionconcatenateAll(...args){returnargs.join('');}
7.7 Используйте синтаксис записи аргументов по умолчанию, а не изменяйте аргументы функции.
// очень плохоfunctionhandleThings(opts){// Нет! Мы не должны изменять аргументы функции.// Плохо вдвойне: если переменная opts будет ложной,// то ей присвоится пустой объект, а не то что вы хотели.// Это приведёт к коварным ошибкам.opts=opts||{};// ...}// всё ещё плохоfunctionhandleThings(opts){if(opts===void0){opts={};}// ...}// хорошоfunctionhandleThings(opts={}){// ...}
7.8 Избегайте побочных эффектов с параметрами по умолчанию.
Почему? И так всё понятно.
varb=1;// плохоfunctioncount(a=b++){console.log(a);}count();// 1count();// 2count(3);// 3count();// 3
7.9 Всегда вставляйте последними параметры по умолчанию. eslint:
default-param-last// плохоfunctionhandleThings(opts={},name){// ...}// хорошоfunctionhandleThings(name,opts={}){// ...}
7.10 Никогда не используйте конструктор функций для создания новых функий. eslint:
no-new-funcПочему? Создание функции в таком духе вычисляет строку подобно
eval(), из-за чего открываются уязвимости.// плохоvaradd=newFunction('a','b','return a + b');// всё ещё плохоvarsubtract=Function('a','b','return a - b');
7.11 Отступы при определении функции. eslint:
space-before-function-parenspace-before-blocksПочему? Однородность кода — это хорошо. Вам не надо будет добавлять или удалять пробел при манипуляции с именем.
// плохоconstf=function(){};constg=function(){};consth=function(){};// хорошоconstx=function(){};consty=functiona(){};
7.12 Никогда не изменяйте параметры. eslint:
no-param-reassignПочему? Манипуляция объектами, приходящими в качестве параметров, может вызывать нежелательные побочные эффекты в вызывающей функции.
// плохоfunctionf1(obj){obj.key=1;}// хорошоfunctionf2(obj){constkey=Object.prototype.hasOwnProperty.call(obj,'key') ?obj.key :1;}
7.13 Никогда не переназначайте параметры. eslint:
no-param-reassignПочему? Переназначенные параметры могут привести к неожиданному поведению, особенно при обращении к
arguments. Это также может вызывать проблемы оптимизации, особенно в V8.// плохоfunctionf1(a){a=1;// ...}functionf2(a){if(!a){a=1;}// ...}// хорошоfunctionf3(a){constb=a||1;// ...}functionf4(a=1){// ...}
7.14 Отдавайте предпочтение использованию синтаксис расширения
...при вызове вариативной функции. eslint:prefer-spreadПочему? Это чище, вам не нужно предоставлять контекст, и не так просто составить
newсapply.// плохоconstx=[1,2,3,4,5];console.log.apply(console,x);// хорошоconstx=[1,2,3,4,5];console.log(...x);// плохоnew(Function.prototype.bind.apply(Date,[null,2016,8,5]));// хорошоnewDate(...[2016,8,5]);
7.15 Функции с многострочным определением или запуском должны содержать такие же отступы, как и другие многострочные списки в этом руководстве: с каждым элементом на отдельной строке, с запятой в конце элемента. eslint:
function-paren-newline// плохоfunctionfoo(bar,baz,quux){// ...}// хорошоfunctionfoo(bar,baz,quux,){// ...}// плохоconsole.log(foo,bar,baz);// хорошоconsole.log(foo,bar,baz,);
8.1 Когда вам необходимо использовать анонимную функцию (например, при передаче встроенной функции обратного вызова), используйте стрелочную функцию. eslint:
prefer-arrow-callback,arrow-spacingПочему? Таким образом создаётся функция, которая выполняется в контексте
this, который мы обычно хотим, а также это более короткий синтаксис.Почему бы и нет? Если у вас есть довольно сложная функция, вы можете переместить эту логику внутрь её собственного именованного функционального выражения.
// плохо[1,2,3].map(function(x){consty=x+1;returnx*y;});// хорошо[1,2,3].map((x)=>{consty=x+1;returnx*y;});
8.2 Если тело функции состоит из одного оператора, возвращающеговыражение без побочных эффектов, то опустите фигурные скобки и используйте неявное возвращение. В противном случае, сохраните фигурные скобки и используйте оператор
return. eslint:arrow-parens,arrow-body-styleПочему? Синтаксический сахар. Когда несколько функций соединены вместе, то это лучше читается.
// плохо[1,2,3].map((number)=>{constnextNumber=number+1;`A string containing the${nextNumber}.`;});// хорошо[1,2,3].map((number)=>`A string containing the${number+1}.`);// хорошо[1,2,3].map((number)=>{constnextNumber=number+1;return`A string containing the${nextNumber}.`;});// хорошо[1,2,3].map((number,index)=>({[index]:number,}));// Неявный возврат с побочными эффектамиfunctionfoo(callback){constval=callback();if(val===true){// Сделать что-то, если функция обратного вызова вернёт true}}letbool=false;// плохоfoo(()=>bool=true);// хорошоfoo(()=>{bool=true;});
8.3 В случае, если выражение располагается на нескольких строках, то необходимо обернуть его в скобки для лучшей читаемости.
Почему? Это чётко показывает, где функция начинается и где заканчивается.
// плохо['get','post','put'].map((httpMethod)=>Object.prototype.hasOwnProperty.call(httpMagicObjectWithAVeryLongName,httpMethod,));// хорошо['get','post','put'].map((httpMethod)=>(Object.prototype.hasOwnProperty.call(httpMagicObjectWithAVeryLongName,httpMethod,)));
8.4 Всегда оборачивайте аргументы круглыми скобками для ясности и согласованности. eslint:
arrow-parensПочему? Минимизирует различия при удалении или добавлении аргументов.
// плохо[1,2,3].map(x=>x*x);// хорошо[1,2,3].map((x)=>x*x);// плохо[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!`));// хорошо[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!`));// плохо[1,2,3].map(x=>{consty=x+1;returnx*y;});// хорошо[1,2,3].map((x)=>{consty=x+1;returnx*y;});
8.5 Избегайте схожести стрелочной функции (
=>) с операторами сравнения (<=,>=). eslint:no-confusing-arrow// плохоconstitemHeight=(item)=>item.height<=256 ?item.largeSize :item.smallSize;// плохоconstitemHeight=(item)=>item.height>=256 ?item.largeSize :item.smallSize;// хорошоconstitemHeight=(item)=>(item.height<=256 ?item.largeSize :item.smallSize);// хорошоconstitemHeight=(item)=>{const{ height, largeSize, smallSize}=item;returnheight<=256 ?largeSize :smallSize;};
8.6 Зафиксируйте расположение тела стрелочной функции с неявным возвратом. eslint:
implicit-arrow-linebreak// плохо(foo)=>bar;(foo)=>(bar);// хорошо(foo)=>bar;(foo)=>(bar);(foo)=>(bar)
9.1 Всегда используйте
class. Избегайте прямых манипуляций сprototype.Почему? Синтаксис
classявляется кратким и понятным.// плохоfunctionQueue(contents=[]){this.queue=[...contents];}Queue.prototype.pop=function(){constvalue=this.queue[0];this.queue.splice(0,1);returnvalue;};// хорошоclassQueue{constructor(contents=[]){this.queue=[...contents];}pop(){constvalue=this.queue[0];this.queue.splice(0,1);returnvalue;}}
9.2 Используйте
extendsдля наследования.Почему? Это встроенный способ наследовать функциональность прототипа, не нарушая
instanceof.// плохоconstinherits=require('inherits');functionPeekableQueue(contents){Queue.apply(this,contents);}inherits(PeekableQueue,Queue);PeekableQueue.prototype.peek=function(){returnthis.queue[0];};// хорошоclassPeekableQueueextendsQueue{peek(){returnthis.queue[0];}}
9.3 Методы могут возвращать
this, чтобы делать цепочки вызовов.// плохоJedi.prototype.jump=function(){this.jumping=true;returntrue;};Jedi.prototype.setHeight=function(height){this.height=height;};constluke=newJedi();luke.jump();// => trueluke.setHeight(20);// => undefined// хорошоclassJedi{jump(){this.jumping=true;returnthis;}setHeight(height){this.height=height;returnthis;}}constluke=newJedi();luke.jump().setHeight(20);
9.4 Вы можете определить свой собственный метод
toString(), просто убедитесь, что он успешно работает и не создаёт никаких побочных эффектов.classJedi{constructor(options={}){this.name=options.name||'no name';}getName(){returnthis.name;}toString(){return`Jedi -${this.getName()}`;}}
9.5 У классов есть конструктор по умолчанию, если он не задан явно. Можно опустить пустой конструктор или конструктор, который только делегирует выполнение родительскому классу. eslint:
no-useless-constructor// плохоclassJedi{constructor(){}getName(){returnthis.name;}}// плохоclassReyextendsJedi{constructor(...args){super(...args);}}// хорошоclassReyextendsJedi{constructor(...args){super(...args);this.name='Rey';}}
9.6 Избегайте дублирующих членов класса. eslint:
no-dupe-class-membersПочему? Если объявление члена класса повторяется, без предупреждения будет использовано последнее. Наличие дубликатов скорее всего приведёт к ошибке.
// плохоclassFoo{bar(){return1;}bar(){return2;}}// хорошоclassFoo{bar(){return1;}}// хорошоclassFoo{bar(){return2;}}
9.7 Метод класса должен использовать
thisили быть преобразованным в статический метод, если только внешняя библиотека или фреймворк не требуют использования определённых нестатических методов. Будучи методом экземпляра, следует указать, что он ведёт себя по-разному в зависимости от свойств получателя. eslint:class-methods-use-this// плохоclassFoo{bar(){console.log('bar');}}// хорошо - используется thisclassFoo{bar(){console.log(this.bar);}}// хорошо - конструктор освобождаетсяclassFoo{constructor(){// ...}}// хорошо - статические методы не должны использовать thisclassFoo{staticbar(){console.log('bar');}}
10.1 Всегда используйте модули (
import/export) вместо нестандартных модульных систем. Вы всегда сможете транспилировать код в вашу любимую модульную систему.Почему? Модули — это будущее. Давайте начнём использовать будущее уже сейчас!
// плохоconstAirbnbStyleGuide=require('./AirbnbStyleGuide');module.exports=AirbnbStyleGuide.es6;// okimportAirbnbStyleGuidefrom'./AirbnbStyleGuide';exportdefaultAirbnbStyleGuide.es6;// отличноimport{es6}from'./AirbnbStyleGuide';exportdefaultes6;
10.2 Не используйте импорт через
*.Почему? Это гарантирует, что у вас есть единственный экспорт по умолчанию.
// плохоimport*asAirbnbStyleGuidefrom'./AirbnbStyleGuide';// хорошоimportAirbnbStyleGuidefrom'./AirbnbStyleGuide';
10.3 Не экспортируйте прямо из импорта.
Почему? Несмотря на то, что запись в одну строку является краткой, разделение на отдельные строки делает вещи последовательными.
// плохо// файл es6.jsexport{es6asdefault}from'./AirbnbStyleGuide';// хорошо// файл es6.jsimport{es6}from'./AirbnbStyleGuide';exportdefaultes6;
10.4 Импортируйте из пути только один раз.eslint:
no-duplicate-importsПочему? Наличие нескольких строк, которые импортируют из одного и того же файла, может сделать код неподдерживаемым.
// плохоimportfoofrom'foo';// … какие-то другие импорты … //import{named1,named2}from'foo';// хорошоimportfoo,{named1,named2}from'foo';// хорошоimportfoo,{named1,named2,}from'foo';
10.5 Не экспортируйте изменяемые переменные.eslint:
import/no-mutable-exportsПочему? Вообще, следует избегать мутации, в особенности при экспорте изменяемых переменных. Несмотря на то, что эта техника может быть необходима в редких случаях, в основном только константа должна быть экспортирована.
// плохоletfoo=3;export{foo};// хорошоconstfoo=3;export{foo};
10.6 В модулях с единственным экспортом предпочтительнее использовать экспорт по умолчанию, а не экспорт по имени.eslint:
import/prefer-default-exportПочему? Для того чтобы поощрять создание множества файлов, которые бы экспортировали одну сущность, т.к. это лучше для читабельности и поддержки кода.
// плохоexportfunctionfoo(){}// хорошоexportdefaultfunctionfoo(){}
10.7 Поместите все импорты выше остальных инструкций.eslint:
import/firstПочему? Так как
importобладает подъёмом, то хранение их всех в начале файла предотвращает от неожиданного поведения.// плохоimportfoofrom'foo';foo.init();importbarfrom'bar';// хорошоimportfoofrom'foo';importbarfrom'bar';foo.init();
10.8 Импорты на нескольких строках должны быть с отступами как у многострочных литералов массива и объекта. eslint:
object-curly-newlineПочему? Фигурные скобки следуют тем же правилам отступа как и любая другая фигурная скобка блока в этом руководстве, тоже самое касается висячих запятых.
// плохоimport{longNameA,longNameB,longNameC,longNameD,longNameE}from'path';// хорошоimport{longNameA,longNameB,longNameC,longNameD,longNameE,}from'path';
10.9 Запретите синтаксис загрузчика Webpack в импорте.eslint:
import/no-webpack-loader-syntaxПочему? Использование Webpack синтаксиса связывает код с упаковщиком модулей. Предпочтительно использовать синтаксис загрузчика в
webpack.config.js.// плохоimportfooSassfrom'css!sass!foo.scss';importbarCssfrom'style!css!bar.css';// хорошоimportfooSassfrom'foo.scss';importbarCssfrom'bar.css';
10.10 Не указывайте JavaScript расширения файловeslint:
import/extensionsПочему? Добавление расширений препятствует рефакторингу и нецелесообразно жёстко программируются детали реализации модуля, который вы импортируете в каждом потребителе.
// плохоimportfoofrom'./foo.js';importbarfrom'./bar.jsx';importbazfrom'./baz/index.jsx';// хорошоimportfoofrom'./foo';importbarfrom'./bar';importbazfrom'./baz';
11.1 Не используйте итераторы. Применяйте функции высшего порядка вместо таких циклов как
for-inилиfor-of. eslint:no-iteratorno-restricted-syntaxПочему? Это обеспечивает соблюдение нашего правила о неизменности переменных. Работать с чистыми функциями, которые возвращают значение, проще, чем с функциями с побочными эффектами.
Используйте
map()/every()/filter()/find()/findIndex()/reduce()/some()/ ... для итерации по массивам, аObject.keys()/Object.values()/Object.entries()для создания массивов, с помощью которых можно итерироваться по объектам.constnumbers=[1,2,3,4,5];// плохоletsum=0;for(letnumofnumbers){sum+=num;}sum===15;// хорошоletsum=0;numbers.forEach((num)=>{sum+=num;});sum===15;// отлично (используйте силу функций)constsum=numbers.reduce((total,num)=>total+num,0);sum===15;// плохоconstincreasedByOne=[];for(leti=0;i<numbers.length;i++){increasedByOne.push(numbers[i]+1);}// хорошоconstincreasedByOne=[];numbers.forEach((num)=>{increasedByOne.push(num+1);});// отлично (продолжайте в том же духе)constincreasedByOne=numbers.map((num)=>num+1);
11.2 Не используйте пока генераторы.
Почему? Они не очень хорошо транспилируются в ES5.
11.3 Если всё-таки необходимо использовать генераторы, или вы не обратили внимания нанаш совет, убедитесь, что
*у функции генератора расположена должным образом. eslint:generator-star-spacingПочему?
functionи*являются частью одного и того же ключевого слова.*не является модификатором дляfunction,function*является уникальной конструкцией, отличной отfunction.// плохоfunction*foo(){// ...}constbar=function*(){// ...};constbaz=function*(){// ...};constquux=function*(){// ...};function*foo(){// ...}function*foo(){// ...}// очень плохоfunction*foo(){// ...}constwat=function*(){// ...};// хорошоfunction*foo(){// ...}constfoo=function*(){// ...};
12.1 Используйте точечную нотацию для доступа к свойствам. eslint:
dot-notationconstluke={jedi:true,age:28,};// плохоconstisJedi=luke['jedi'];// хорошоconstisJedi=luke.jedi;
12.2 Используйте скобочную нотацию
[], когда название свойства хранится в переменной.constluke={jedi:true,age:28,};functiongetProp(prop){returnluke[prop];}constisJedi=getProp('jedi');
12.3 Используйте оператор
**для возведения в степень. eslint:no-restricted-properties.// плохоconstbinary=Math.pow(2,10);// хорошоconstbinary=2**10;
13.1 Всегда используйте
constилиletдля объявления переменных. Невыполнение этого требования приведёт к появлению глобальных переменных. Необходимо избегать загрязнения глобального пространства имён. eslint:no-undefprefer-const// плохоsuperPower=newSuperPower();// хорошоconstsuperPower=newSuperPower();
13.2 Используйте объявление
constилиletдля каждой переменной или присвоения. eslint:one-varПочему? Таким образом проще добавить новые переменные. Также вы никогда не будете беспокоиться о перемещении
;и,и об отображении изменений в пунктуации. Вы также можете пройтись по каждому объявлению с помощью отладчика, вместо того, чтобы прыгать через все сразу.// плохоconstitems=getItems(),goSportsTeam=true,dragonball='z';// плохо// (сравните с кодом выше и попытайтесь найти ошибку)constitems=getItems(),goSportsTeam=true;dragonball='z';// хорошоconstitems=getItems();constgoSportsTeam=true;constdragonball='z';
13.3 В первую очередь группируйте
const, а затемlet.Почему? Это полезно, когда в будущем вам понадобится создать переменную, зависимую от предыдущих.
// плохоleti,len,dragonball,items=getItems(),goSportsTeam=true;// плохоleti;constitems=getItems();letdragonball;constgoSportsTeam=true;letlen;// хорошоconstgoSportsTeam=true;constitems=getItems();letdragonball;leti;letlength;
13.4 Создавайте переменные там, где они вам необходимы, но помещайте их в подходящее место.
Почему?
letиconstимеют блочную область видимости, а не функциональную.// плохо - вызов ненужной функцииfunctioncheckName(hasName){constname=getName();if(hasName==='test'){returnfalse;}if(name==='test'){this.setName('');returnfalse;}returnname;}// хорошоfunctioncheckName(hasName){if(hasName==='test'){returnfalse;}constname=getName();if(name==='test'){this.setName('');returnfalse;}returnname;}
13.5 Не создавайте цепочки присваивания переменных. eslint:
no-multi-assignПочему? Такие цепочки создают неявные глобальные переменные.
// плохо(functionexample(){// JavaScript интерпретирует это, как// let a = ( b = ( c = 1 ) );// Ключевое слово let применится только к переменной a;// переменные b и c станут глобальными.leta=b=c=1;}());console.log(a);// throws ReferenceErrorconsole.log(b);// 1console.log(c);// 1// хорошо(functionexample(){leta=1;letb=a;letc=a;}());console.log(a);// throws ReferenceErrorconsole.log(b);// throws ReferenceErrorconsole.log(c);// throws ReferenceError// тоже самое и для `const`
13.6 Избегайте использования унарных инкрементов и декрементов (
++,--). eslintno-plusplusПочему? Согласно документации eslint, унарные инкремент и декремент автоматически вставляют точку с запятой, что может стать причиной трудноуловимых ошибок при инкрементировании и декрементировании значений. Также нагляднее изменять ваши значения таким образом
num += 1вместоnum++илиnum ++. Запрет на унарные инкремент и декремент ограждает вас от непреднамеренных преждевременных инкрементаций/декрементаций значений, которые могут привести к непредсказуемому поведению вашей программы.// плохоconstarray=[1,2,3];letnum=1;num++;--num;letsum=0;lettruthyCount=0;for(leti=0;i<array.length;i++){letvalue=array[i];sum+=value;if(value){truthyCount++;}}// хорошоconstarray=[1,2,3];letnum=1;num+=1;num-=1;constsum=array.reduce((a,b)=>a+b,0);consttruthyCount=array.filter(Boolean).length;
13.7 В присвоении избегайте разрывов строк до и после
=. Если ваше присвоение нарушает правилоmax-len, оберните значение в круглые скобки. eslintoperator-linebreak.Почему? Разрывы строк до и после
=могут приводить к путанице в понимании значения.// плохоconstfoo=superLongLongLongLongLongLongLongLongFunctionName();// плохоconstfoo='superLongLongLongLongLongLongLongLongString';// хорошоconstfoo=(superLongLongLongLongLongLongLongLongFunctionName());// хорошоconstfoo='superLongLongLongLongLongLongLongLongString';
13.8 Запретить неиспользуемые переменные. eslint:
no-unused-varsПочему? Переменные, которые объявлены и не используются в коде, скорее всего, являются ошибкой из-за незавершённого рефакторинга. Такие переменные занимают место в коде и могут привести к путанице при чтении.
// плохоvarsome_unused_var=42;// Переменные, которые используются только для записи, не считаются используемыми.vary=10;y=5;// Чтение для собственной модификации.varz=0;z=z+1;// Неиспользуемые аргументы функции.functiongetX(x,y){returnx;}// хорошоfunctiongetXPlusY(x,y){returnx+y;}varx=1;vary=a+2;alert(getXPlusY(x,y));// Переменная 'type' игнорируется, даже если она не испольуется, потому что рядом есть rest-свойство.// Эта форма извлечения объекта, которая опускает указанные ключи.var{ type, ...coords}=data;// 'coords' теперь 'data' объект без свойства 'type'.
14.1 Объявления
varподнимаются в начало области видимости ближайшей закрывающей их функции, а их присвоение нет. Объявленияconstиletработают по новой концепции называемойВременные Мёртвые Зоны (Temporal Dead Zone). Важно знать, почему использоватьtypeof больше не безопасно.// мы знаем, что это не будет работать// (если нет глобальной переменной notDefined)functionexample(){console.log(notDefined);// => выбросит ошибку ReferenceError}// обращение к переменной до её создания// будет работать из-за подъёма.// Примечание: значение true не поднимается.functionexample(){console.log(declaredButNotAssigned);// => undefinedvardeclaredButNotAssigned=true;}// интерпретатор понимает объявление// переменной в начало области видимости.// это означает, что наш пример// можно переписать таким образом:functionexample(){letdeclaredButNotAssigned;console.log(declaredButNotAssigned);// => undefineddeclaredButNotAssigned=true;}// использование const и letfunctionexample(){console.log(declaredButNotAssigned);// => выбросит ошибку ReferenceErrorconsole.log(typeofdeclaredButNotAssigned);// => выбросит ошибку ReferenceErrorconstdeclaredButNotAssigned=true;}
14.2 Для анонимных функциональных выражений наверх области видимости поднимается название переменной, но не её значение.
functionexample(){console.log(anonymous);// => undefinedanonymous();// => TypeError anonymous не является функциейvaranonymous=function(){console.log('anonymous function expression');};}
14.3 Для именованных функциональных выражений наверх области видимости поднимается название переменной, но не имя или тело функции.
functionexample(){console.log(named);// => undefinednamed();// => TypeError named не является функциейsuperPower();// => ReferenceError superPower не определенаvarnamed=functionsuperPower(){console.log('Flying');};}// тоже самое справедливо, когда имя функции// совпадает с именем переменной.functionexample(){console.log(named);// => undefinednamed();// => TypeError named не является функциейvarnamed=functionnamed(){console.log('named');};}
14.4 При объявлении функции её имя и тело поднимаются наверх области видимости.
functionexample(){superPower();// => FlyingfunctionsuperPower(){console.log('Flying');}}
Более подробно можно прочитать в статьеJavaScript Scoping & Hoisting отBen Cherry.
15.2 Условные операторы, такие как
if, вычисляются путём приведения к логическому типуBooleanчерез абстрактный методToBooleanи всегда следуют следующим правилам:- Object соответствуетtrue
- Undefined соответствуетfalse
- Null соответствуетfalse
- Boolean соответствуетзначению булева типа
- Number соответствуетfalse, если+0, -0, or NaN, в остальных случаяхtrue
- String соответствуетfalse, если строка пустая
'', в остальных случаяхtrue
if([0]&&[]){// true// Массив (даже пустой) является объектом, а объекты возвращают true}
15.3 Используйте сокращения для булевских типов, а для строк и чисел применяйте явное сравнение.
// плохоif(isValid===true){// ...}// хорошоif(isValid){// ...}// плохоif(name){// ...}// хорошоif(name!==''){// ...}// плохоif(collection.length){// ...}// хорошоif(collection.length>0){// ...}
- 15.4 Более подробную информацию можно узнать в статьеTruth Equality and JavaScript от Angus Croll.
15.5 Используйте фигурные скобки для
caseиdefault, если они содержат лексические декларации (например,let,const,function, иclass). eslint:no-case-declarations.Почему? Лексические декларации видны во всем
switchблоке, но инициализируются только при присваивании, которое происходит при входе в блокcase. Возникают проблемы, когда множествоcaseпытаются определить одно и то же.// плохоswitch(foo){case1:letx=1;break;case2:consty=2;break;case3:functionf(){// ...}break;default:classC{}}// хорошоswitch(foo){case1:{letx=1;break;}case2:{consty=2;break;}case3:{functionf(){// ...}break;}case4:bar();break;default:{classC{}}}
15.6 Тернарные операторы не должны быть вложены и в большинстве случаев должны быть расположены на одной строке. eslint:
no-nested-ternary.// плохоconstfoo=maybe1>maybe2 ?"bar" :value1>value2 ?"baz" :null;// разбит на два отдельных тернарных выраженияconstmaybeNull=value1>value2 ?'baz' :null;constfoo=maybe1>maybe2 ?'bar' :maybeNull;// отличноconstfoo=maybe1>maybe2 ?'bar' :maybeNull;
15.7 Избегайте ненужных тернарных операторов. eslint:
no-unneeded-ternary.// плохоconstfoo=a ?a :b;constbar=c ?true :false;constbaz=c ?false :true;// хорошоconstfoo=a||b;constbar=!!c;constbaz=!c;
15.8 При смешивании операторов, помещайте их в круглые скобки. Единственным исключением являются стандартные арифметические операторы:
+,-и**, так как их приоритет широко известен. Мы рекомендуем заключить/и*в круглые скобки, поскольку их приоритет может быть неоднозначным, когда они смешиваются. eslint:no-mixed-operatorsПочему? Это улучшает читаемость и уточняет намерения разработчика.
// плохоconstfoo=a&&b<0||c>0||d+1===0;// плохоconstbar=a**b-5%d;// плохо// можно ошибиться, думая что это (a || b) && cif(a||b&&c){returnd;}// плохоconstbar=a+b/c*d;// хорошоconstfoo=(a&&b<0)||c>0||(d+1===0);// хорошоconstbar=a**b-(5%d);// хорошоif(a||(b&&c)){returnd;}// хорошоconstbar=a+(b/c)*d;
16.1 Используйте фигурные скобки, когда блок кода занимает несколько строк. eslint:
nonblock-statement-body-position// плохоif(test)returnfalse;// хорошоif(test)returnfalse;// хорошоif(test){returnfalse;}// плохоfunctionfoo(){returnfalse;}// хорошоfunctionbar(){returnfalse;}
16.2 Если блоки кода в условии
ifиelseзанимают несколько строк, расположите операторelseна той же строчке, где находится закрывающая фигурная скобка блокаif. eslint:brace-style// плохоif(test){thing1();thing2();}else{thing3();}// хорошоif(test){thing1();thing2();}else{thing3();}
16.3 Если в блоке
ifвсегда выполняется операторreturn, последующий блокelseне нужен.returnвнутри блокаelse if, следующем за блокомif, который содержитreturn, может быть разделён на несколько блоковif. eslint:no-else-return// плохоfunctionfoo(){if(x){returnx;}else{returny;}}// плохоfunctioncats(){if(x){returnx;}elseif(y){returny;}}// плохоfunctiondogs(){if(x){returnx;}else{if(y){returny;}}}// хорошоfunctionfoo(){if(x){returnx;}returny;}// хорошоfunctioncats(){if(x){returnx;}if(y){returny;}}// хорошоfunctiondogs(x){if(x){if(z){returny;}}else{returnz;}}
17.1 Если ваш управляющий оператор (
if,whileи т.д.) слишком длинный или превышает максимальную длину строки, то каждое (сгруппированное) условие можно поместить на новую строку. Логический оператор должен располагаться в начале строки.Почему? Наличие операторов в начале строки приводит к выравниванию операторов и напоминает цепочку методов. Это также улучшает читаемость, упрощая визуальное отслеживание сложной логики.
// плохоif((foo===123||bar==='abc')&&doesItLookGoodWhenItBecomesThatLong()&&isThisReallyHappening()){thing1();}// плохоif(foo===123&&bar==='abc'){thing1();}// плохоif(foo===123&&bar==='abc'){thing1();}// плохоif(foo===123&&bar==='abc'){thing1();}// хорошоif(foo===123&&bar==='abc'){thing1();}// хорошоif((foo===123||bar==='abc')&&doesItLookGoodWhenItBecomesThatLong()&&isThisReallyHappening()){thing1();}// хорошоif(foo===123&&bar==='abc'){thing1();}
17.2 Не используйте операторы выбора вместо управляющих операторов.
// плохо!isRunning&&startRunning();// хорошоif(!isRunning){startRunning();}
18.1 Используйте конструкцию
/** ... */для многострочных комментариев.// плохо// make() возвращает новый элемент// соответствующий переданному названию тега////@param {String} tag//@return {Element} elementfunctionmake(tag){// ...returnelement;}// хорошо/** * make() возвращает новый элемент * соответствующий переданному названию тега */functionmake(tag){// ...returnelement;}
18.2 Используйте двойной слеш
//для однострочных комментариев. Располагайте такие комментарии отдельной строкой над кодом, который хотите пояснить. Если комментарий не является первой строкой блока, добавьте сверху пустую строку.// плохоconstactive=true;// это текущая вкладка// хорошо// это текущая вкладкаconstactive=true;// плохоfunctiongetType(){console.log('fetching type...');// установить по умолчанию тип 'no type'consttype=this.type||'no type';returntype;}// хорошоfunctiongetType(){console.log('fetching type...');// установить по умолчанию тип 'no type'consttype=this.type||'no type';returntype;}// тоже хорошоfunctiongetType(){// установить по умолчанию тип 'no type'consttype=this.type||'no type';returntype;}
18.3 Начинайте все комментарии с пробела, так их проще читать. eslint:
spaced-comment// плохо//это текущая вкладкаconstactive=true;// хорошо// это текущая вкладкаconstactive=true;// плохо/** *make() возвращает новый элемент *соответствующий переданному названию тега */functionmake(tag){// ...returnelement;}// хорошо/** * make() возвращает новый элемент * соответствующий переданному названию тега */functionmake(tag){// ...returnelement;}
- 18.4 Если комментарий начинается со слов
FIXMEилиTODO, то это помогает другим разработчикам быстро понять, когда вы хотите указать на проблему, которую надо решить, или когда вы предлагаете решение проблемы, которое надо реализовать. Такие комментарии, в отличие от обычных, побуждают к действию:FIXME: -- нужно разобраться с этимилиTODO: -- нужно реализовать.
18.5 Используйте
// FIXME:, чтобы описать проблему.classCalculatorextendsAbacus{constructor(){super();// FIXME: здесь не должна использоваться глобальная переменнаяtotal=0;}}
18.6 Используйте
// TODO:, чтобы описать решение проблемы.classCalculatorextendsAbacus{constructor(){super();// TODO: нужна возможность задать total через параметрыthis.total=0;}}
19.1 Используйте мягкую табуляцию (символ пробела) шириной в 2 пробела. eslint:
indent// плохоfunctionfoo(){∙∙∙∙letname;}// плохоfunctionbar(){∙letname;}// хорошоfunctionbaz(){∙∙letname;}
19.2 Ставьте 1 пробел перед открывающей фигурной скобкой у блока. eslint:
space-before-blocks// плохоfunctiontest(){console.log('test');}// хорошоfunctiontest(){console.log('test');}// плохоdog.set('attr',{age:'1 year',breed:'Bernese Mountain Dog',});// хорошоdog.set('attr',{age:'1 year',breed:'Bernese Mountain Dog',});
19.3 Ставьте 1 пробел перед открывающей круглой скобкой в операторах управления (
if,whileи т.п.). Не оставляйте пробелов между списком аргументов и названием в объявлениях и вызовах функций. eslint:keyword-spacing// плохоif(isJedi){fight();}// хорошоif(isJedi){fight();}// плохоfunctionfight(){console.log('Swooosh!');}// хорошоfunctionfight(){console.log('Swooosh!');}
19.4 Разделяйте операторы пробелами. eslint:
space-infix-ops// плохоconstx=y+5;// хорошоconstx=y+5;
19.5 В конце файла оставляйте одну пустую строку. eslint:
eol-last// плохоimport{es6}from'./AirbnbStyleGuide';// ...exportdefaultes6;
// плохоimport{es6}from'./AirbnbStyleGuide';// ...exportdefaultes6;↵↵
// хорошоimport{es6}from'./AirbnbStyleGuide';// ...exportdefaultes6;↵
19.6 Используйте переносы строк и отступы, когда делаете длинные цепочки методов (больше 2 методов). Ставьте точку в начале строки, чтобы дать понять, что это не новая инструкция, а продолжение цепочки. eslint:
newline-per-chained-callno-whitespace-before-property// плохо$('#items').find('.selected').highlight().end().find('.open').updateCount();// плохо$('#items').find('.selected').highlight().end().find('.open').updateCount();// хорошо$('#items').find('.selected').highlight().end().find('.open').updateCount();// плохоconstleds=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);// хорошоconstleds=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);// хорошоconstleds=stage.selectAll('.led').data(data);constsvg=leds.enter().append('svg:svg');svg.classed('led',true).attr('width',(radius+margin)*2);constg=svg.append('svg:g');g.attr('transform',`translate(${radius+margin},${radius+margin})`).call(tron.led);
19.7 Оставляйте пустую строку между блоком кода и следующей инструкцией.
// плохоif(foo){returnbar;}returnbaz;// хорошоif(foo){returnbar;}returnbaz;// плохоconstobj={foo(){},bar(){},};returnobj;// хорошоconstobj={foo(){},bar(){},};returnobj;// плохоconstarr=[functionfoo(){},functionbar(){},];returnarr;// хорошоconstarr=[functionfoo(){},functionbar(){},];returnarr;
19.8 Не добавляйте отступы до или после кода внутри блока. eslint:
padded-blocks// плохоfunctionbar(){console.log(foo);}// тоже плохоif(baz){console.log(qux);}else{console.log(foo);}// хорошоfunctionbar(){console.log(foo);}// хорошоif(baz){console.log(qux);}else{console.log(foo);}
19.9 Не используйте множество пустых строк для заполнения кода. eslint:
no-multiple-empty-lines// плохоclassPerson{constructor(fullName,email,birthday){this.fullName=fullName;this.email=email;this.setAge(birthday);}setAge(birthday){consttoday=newDate();constage=this.getAge(today,birthday);this.age=age;}getAge(today,birthday){// ..}}// хорошоclassPerson{constructor(fullName,email,birthday){this.fullName=fullName;this.email=email;this.setAge(birthday);}setAge(birthday){consttoday=newDate();constage=getAge(today,birthday);this.age=age;}getAge(today,birthday){// ..}}
19.10 Не добавляйте пробелы между круглыми скобками и их содержимым. eslint:
space-in-parens// плохоfunctionbar(foo){returnfoo;}// хорошоfunctionbar(foo){returnfoo;}// плохоif(foo){console.log(foo);}// хорошоif(foo){console.log(foo);}
19.11 Не добавляйте пробелы между квадратными скобками и их содержимым. eslint:
array-bracket-spacing// плохоconstfoo=[1,2,3];console.log(foo[0]);// хорошоconstfoo=[1,2,3];console.log(foo[0]);
19.12 Добавляйте пробелы между фигурными скобками и их содержимым. eslint:
object-curly-spacing// плохоconstfoo={clark:'kent'};// хорошоconstfoo={clark:'kent'};
19.13 Старайтесь не допускать, чтобы строки были длиннее 100 символов (включая пробелы). Замечание: согласнопункту выше, длинные строки с текстом освобождаются от этого правила и не должны разбиваться на несколько строк. eslint:
max-lenПочему? Это обеспечивает удобство чтения и поддержки кода.
// плохоconstfoo=jsonData&&jsonData.foo&&jsonData.foo.bar&&jsonData.foo.bar.baz&&jsonData.foo.bar.baz.quux&&jsonData.foo.bar.baz.quux.xyzzy;// плохо$.ajax({method:'POST',url:'https://airbnb.com/',data:{name:'John'}}).done(()=>console.log('Congratulations!')).fail(()=>console.log('You have failed this city.'));// хорошоconstfoo=jsonData&&jsonData.foo&&jsonData.foo.bar&&jsonData.foo.bar.baz&&jsonData.foo.bar.baz.quux&&jsonData.foo.bar.baz.quux.xyzzy;// хорошо$.ajax({method:'POST',url:'https://airbnb.com/',data:{name:'John'},}).done(()=>console.log('Congratulations!')).fail(()=>console.log('You have failed this city.'));
19.14 Требуйте согласованного расстояния между открывающим символом блока и следующим символом на одной и той же строке. Тоже самое касается расстояния между закрывающим символом блока и предыдущим символом. eslint:
block-spacing// плохоfunctionfoo(){returntrue;}if(foo){bar=0;}// хорошоfunctionfoo(){returntrue;}if(foo){bar=0;}
19.15 Избегайте пробелов перед запятыми и ставьте его после. eslint:
comma-spacing// плохоvarfoo=1,bar=2;vararr=[1,2];// хорошоvarfoo=1,bar=2;vararr=[1,2];
19.16 Избегайте пробелов внутри скобок вычисляемого свойства. eslint:
computed-property-spacing// плохоobj[foo]obj['foo']varx={[b]:a}obj[foo[bar]]// хорошоobj[foo]obj['foo']varx={[b]:a}obj[foo[bar]]
19.17 Избегайте пробелов между функциями и их вызовами. eslint:
func-call-spacing// плохоfunc();func();// хорошоfunc();
19.18 Обеспечьте согласованное расстояние между ключами и значениями в свойствах литералов объекта. eslint:
key-spacing// плохоvarobj={foo :42};varobj2={foo:42};// хорошоvarobj={foo:42};
- 19.19 Избегайте пробелов в конце строки. eslint:
no-trailing-spaces
19.20 Избегайте множества пустых строк и новой строки в начале файлов. Разрешайте только одну пустую строку в конце файла. eslint:
no-multiple-empty-lines// плохо - множество пустых строкvarx=1;vary=2;// плохо - 2+ новых строк в конце файлаvarx=1;vary=2;// плохо - 1+ новая строка в начале файлаvarx=1;vary=2;// хорошоvarx=1;vary=2;
20.1 Не начинайте строку с запятой. eslint:
comma-style// плохоconststory=[once,upon,aTime];// хорошоconststory=[once,upon,aTime,];// плохоconsthero={firstName:'Ada',lastName:'Lovelace',birthYear:1815,superPower:'computers'};// хорошоconsthero={firstName:'Ada',lastName:'Lovelace',birthYear:1815,superPower:'computers',};
20.2 Добавляйте висячие запятые. eslint:
comma-dangleПочему? Такой подход даёт понятную разницу при просмотре изменений. Кроме того, транспиляторы типа Babel удалят висячие запятые из собранного кода, поэтому вы можете не беспокоиться опроблемах в старых браузерах.
// плохо - git diff без висячей запятойconst hero = { firstName: 'Florence',- lastName: 'Nightingale'+ lastName: 'Nightingale',+ inventorOf: ['coxcomb chart', 'modern nursing']};// хорошо - git diff с висячей запятойconst hero = { firstName: 'Florence', lastName: 'Nightingale',+ inventorOf: ['coxcomb chart', 'modern nursing'],};// плохоconsthero={firstName:'Dana',lastName:'Scully'};constheroes=['Batman','Superman'];// хорошоconsthero={firstName:'Dana',lastName:'Scully',};constheroes=['Batman','Superman',];// плохоfunctioncreateHero(firstName,lastName,inventorOf){// ничего не делает}// хорошоfunctioncreateHero(firstName,lastName,inventorOf,){// ничего не делает}// хорошо (обратите внимание, что висячей запятой не должно быть после rest-параметра)functioncreateHero(firstName,lastName,inventorOf, ...heroArgs){// ничего не делает}// плохоcreateHero(firstName,lastName,inventorOf);// хорошоcreateHero(firstName,lastName,inventorOf,);// хорошо (обратите внимание, что висячей запятой не должно быть после rest-аргумента)createHero(firstName,lastName,inventorOf, ...heroArgs);
Почему? Когда JavaScript встречает перенос строки без точки с запятой, он использует правило под названиемАвтоматическая Вставка Точки с запятой (Automatic Semicolon Insertion), чтобы определить, стоит ли считать этот перенос строки как конец выражения и (как следует из названия) поместить точку с запятой в вашем коде до переноса строки. Однако, ASI содержит несколько странных форм поведения, и ваш код может быть сломан, если JavaScript неверно истолкует ваш перенос строки. Эти правила станут сложнее, когда новые возможности станут частью JavaScript. Явное завершение ваших выражений и настройка вашего линтера для улавливания пропущенных точек с запятыми помогут вам предотвратить возникновение проблем.
// плохо - выбрасывает исключениеconstluke={}constleia={}[luke,leia].forEach((jedi)=>jedi.father='vader')// плохо - выбрасывает исключениеconstreaction="No! That’s impossible!"(asyncfunctionmeanwhileOnTheFalcon(){// переносимся к `leia`, `lando`, `chewie`, `r2`, `c3p0`// ...}())// плохо - возвращает `undefined` вместо значения на следующей строке. Так всегда происходит, когда `return` расположен сам по себе, потому что ASI (Автоматическая Вставка Точки с запятой)!functionfoo(){return'search your feelings, you know it to be foo'}// хорошоconstluke={};constleia={};[luke,leia].forEach((jedi)=>{jedi.father='vader';});// хорошоconstreaction="No! That’s impossible!";(asyncfunctionmeanwhileOnTheFalcon(){// переносимся к `leia`, `lando`, `chewie`, `r2`, `c3p0`// ...}());// хорошоfunctionfoo(){return'search your feelings, you know it to be foo';}
- 22.1 Выполняйте приведение типов в начале инструкции.
22.2 Строки: eslint:
no-new-wrappers// => this.reviewScore = 9;// плохоconsttotalScore=newString(this.reviewScore);// тип totalScore будет "object", а не "string"// плохоconsttotalScore=this.reviewScore+'';// вызывает this.reviewScore.valueOf()// плохоconsttotalScore=this.reviewScore.toString();// нет гарантии что вернётся строка// хорошоconsttotalScore=String(this.reviewScore);
22.3 Числа: Используйте
NumberиparseIntс основанием системы счисления. eslint:radixno-new-wrappersПочему? Функция
parseIntвыдаёт целочисленное значение на основе интерпретации содержимого строкового аргумента в соответствии с указанным основанием. Начальный пробел в строке игнорируется. Если основание "не определено" или "0", предполагается, что оно равно "10", за исключением случаев, когда число начинается с пар символов "0x" или "0X", в этом случае предполагается, что основание равно 16. Это отличается от ECMAScript 3, который просто не поощрял (но разрешал) восьмеричную интерпретацию. Многие реализации не приняли такое поведение по состоянию на 2013 год. И, поскольку должны поддерживаться более старые браузеры, всегда указывайте основание.constinputValue='4';// плохоconstval=newNumber(inputValue);// плохоconstval=+inputValue;// плохоconstval=inputValue>>0;// плохоconstval=parseInt(inputValue);// хорошоconstval=Number(inputValue);// хорошоconstval=parseInt(inputValue,10);
22.4 Если по какой-то причине вы делаете что-то настолько безумное, что
parseIntявляется слабым местом и вам нужно использовать побитовый сдвиг из-завопросов производительности, оставьте комментарий, объясняющий почему и что вы делаете.// хорошо/** * этот код медленно работал из-за parseInt. * побитовый сдвиг строки для приведения её к числу * работает значительно быстрее. */constval=inputValue>>0;
22.5Примечание: Будьте осторожны с побитовыми операциями. Числа в JavaScript являются64-битными значениями, но побитовые операции всегда возвращают 32-битные значения (источник). Побитовый сдвиг может привести к неожиданному поведению для значений больше, чем 32 бита.Обсуждение. Верхний предел — 2 147 483 647:
2147483647>>0;// => 21474836472147483648>>0;// => -21474836482147483649>>0;// => -2147483647
22.6 Логические типы: eslint:
no-new-wrappersconstage=0;// плохоconsthasAge=newBoolean(age);// хорошоconsthasAge=Boolean(age);// отличноconsthasAge=!!age;
23.1 Избегайте названий из одной буквы. Имя должно быть наглядным. eslint:
id-length// плохоfunctionq(){// ...}// хорошоfunctionquery(){// ...}
23.2 Используйте
camelCaseдля именования объектов, функций и экземпляров. eslint:camelcase// плохоconstOBJEcttsssss={};constthis_is_my_object={};functionc(){}// хорошоconstthisIsMyObject={};functionthisIsMyFunction(){}
23.3 Используйте
PascalCaseтолько для именования конструкторов и классов. eslint:new-cap// плохоfunctionuser(options){this.name=options.name;}constbad=newuser({name:'nope',});// хорошоclassUser{constructor(options){this.name=options.name;}}constgood=newUser({name:'yup',});
23.4 Не используйте
_в начале или в конце названий. eslint:no-underscore-dangleПочему? JavaScript не имеет концепции приватности свойств или методов. Хотя подчёркивание в начале имени является распространённым соглашением, которое показывает «приватность», фактически эти свойства являются такими же доступными, как и часть вашего публичного API. Это соглашение может привести к тому, что разработчики будут ошибочно думать, что изменения не приведут к поломке или что тесты не нужны. Итог: если вы хотите, чтобы что-то было «приватным», то оно не должно быть доступно извне.
// плохоthis.__firstName__='Panda';this.firstName_='Panda';this._firstName='Panda';// хорошоthis.firstName='Panda';// хорошо, в средах, где поддерживается WeakMaps// смотрите https://kangax.github.io/compat-table/es6/#test-WeakMapconstfirstNames=newWeakMap();firstNames.set(this,'Panda');
23.5 Не сохраняйте ссылку на
this. Используйте стрелочные функции илиметод bind().// плохоfunctionfoo(){constself=this;returnfunction(){console.log(self);};}// плохоfunctionfoo(){constthat=this;returnfunction(){console.log(that);};}// хорошоfunctionfoo(){return()=>{console.log(this);};}
23.6 Название файла точно должно совпадать с именем его экспорта по умолчанию.
// содержание файла 1classCheckBox{// ...}exportdefaultCheckBox;// содержание файла 2exportdefaultfunctionfortyTwo(){return42;}// содержание файла 3exportdefaultfunctioninsideDirectory(){}// в других файлах// плохоimportCheckBoxfrom'./checkBox';// PascalCase import/export, camelCase filenameimportFortyTwofrom'./FortyTwo';// PascalCase import/filename, camelCase exportimportInsideDirectoryfrom'./InsideDirectory';// PascalCase import/filename, camelCase export// плохоimportCheckBoxfrom'./check_box';// PascalCase import/export, snake_case filenameimportforty_twofrom'./forty_two';// snake_case import/filename, camelCase exportimportinside_directoryfrom'./inside_directory';// snake_case import, camelCase exportimportindexfrom'./inside_directory/index';// requiring the index file explicitlyimportinsideDirectoryfrom'./insideDirectory/index';// requiring the index file explicitly// хорошоimportCheckBoxfrom'./CheckBox';// PascalCase export/import/filenameimportfortyTwofrom'./fortyTwo';// camelCase export/import/filenameimportinsideDirectoryfrom'./insideDirectory';// camelCase export/import/directory name/implicit "index"// ^ поддерживает оба варианта: insideDirectory.js и insideDirectory/index.js
23.7 Используйте
camelCase, когда экспортируете функцию по умолчанию. Ваш файл должен называться так же, как и имя функции.functionmakeStyleGuide(){// ...}exportdefaultmakeStyleGuide;
23.8 Используйте
PascalCase, когда экспортируете конструктор / класс / синглтон / библиотечную функцию / объект.constAirbnbStyleGuide={es6:{},};exportdefaultAirbnbStyleGuide;
23.9 Сокращения или буквенные аббревиатуры всегда должны быть в верхнем или нижнем регистре.
Почему? Имена предназначены для удобства чтения.
// плохоimportSmsContainerfrom'./containers/SmsContainer';// плохоconstHttpRequests=[// ...];// хорошоimportSMSContainerfrom'./containers/SMSContainer';// хорошоconstHTTPRequests=[// ...];// также хорошоconsthttpRequests=[// ...];// отличноimportTextMessageContainerfrom'./containers/TextMessageContainer';// отличноconstrequests=[// ...];
- 24.1 Функции-аксессоры для свойств объекта больше не нужны.
24.2 Не используйте геттеры/сеттеры, т.к. они вызывают неожиданные побочные эффекты, а также их тяжело тестировать, поддерживать и понимать. Вместо этого создавайте методы
getVal()иsetVal('hello').// плохоclassDragon{getage(){// ...}setage(value){// ...}}// хорошоclassDragon{getAge(){// ...}setAge(value){// ...}}
24.3 Если свойство/метод возвращает логический тип, то используйте названия
isVal()илиhasVal().// плохоif(!dragon.age()){returnfalse;}// хорошоif(!dragon.hasAge()){returnfalse;}
24.4 Можно создавать функции
get()иset(), но нужно быть последовательным.classJedi{constructor(options={}){constlightsaber=options.lightsaber||'blue';this.set('lightsaber',lightsaber);}set(key,val){this[key]=val;}get(key){returnthis[key];}}
25.1 Когда привязываете данные к событию (например, события
DOMили какие-то собственные события, какBackboneсобытия), передавайте литерал объекта (также известный как «хэш») вместо простого значения. Это позволяет другим разработчикам добавлять больше данных без поиска и изменения каждого обработчика события. К примеру, вместо:// плохо$(this).trigger('listingUpdated',listing.id);// ...$(this).on('listingUpdated',(e,listingID)=>{// делает что-то с listingID});
предпочитайте:
// хорошо$(this).trigger('listingUpdated',{listingID:listing.id});// ...$(this).on('listingUpdated',(e,data)=>{// делает что-то с data.listingID});
26.1 Начинайте названия переменных, хранящих объект jQuery, со знака
$.// плохоconstsidebar=$('.sidebar');// хорошоconst$sidebar=$('.sidebar');// хорошоconst$sidebarBtn=$('.sidebar-btn');
26.2 Кэшируйте jQuery-поиски.
// плохоfunctionsetSidebar(){$('.sidebar').hide();// ...$('.sidebar').css({'background-color':'pink',});}// хорошоfunctionsetSidebar(){const$sidebar=$('.sidebar');$sidebar.hide();// ...$sidebar.css({'background-color':'pink',});}
- 26.3 Для поиска в DOM используйте каскады
$('.sidebar ul')или селектор родитель > ребёнок$('.sidebar > ul').jsPerf
26.4 Используйте функцию
findдля поиска в сохранённых jQuery-объектах.// плохо$('ul','.sidebar').hide();// плохо$('.sidebar').find('ul').hide();// хорошо$('.sidebar ul').hide();// хорошо$('.sidebar > ul').hide();// хорошо$sidebar.find('ul').hide();
- 27.1 Можно посмотреть втаблице поддержки ES5 от пользователяKangax .
- 28.1 Здесь собраны ссылки на различные возможности ES6.
- Стрелочные функции
- Классы и конструкторы
- Сокращённая запись методов объекта
- Сокращённая запись свойств объекта
- Вычисляемые имена свойств объекта
- Шаблонные строки
- Деструктуризация
- Параметры по умолчанию
- Оставшиеся параметры
- Оператор расширения
- Let и Const
- Итераторы и генераторы
- Модули
28.2 Не используйтепредложения TC39, которые не перешли на 3-ю стадию.
Почему?Они ещё не закончены и могут быть изменены или полностью изъяты. Мы хотим использовать JavaScript, а предложения ещё не стали частью JavaScript.
Стандартная библиотекасодержит утилиты, функциональность которых сломана, но они остались для поддержки старого кода.
29.1 Используйте
Number.isNaNвместо глобальногоisNaN.eslint:no-restricted-globalsПочему? Глобальная функция
isNaNприводит не-числа к числам, возвращаяtrueдля всего, что приводится кNaN.Если такое поведение необходимо, сделайте его явным.// плохоisNaN('1.2');// falseisNaN('1.2.3');// true// хорошоNumber.isNaN('1.2.3');// falseNumber.isNaN(Number('1.2.3'));// true
29.2 Используйте
Number.isFiniteвместо глобальногоisFinite.eslint:no-restricted-globalsПочему? Глобальная функция
isFiniteприводит не-числа к числам, возвращаяtrueдля всего, что приводится к конечному числу.Если такое поведение необходимо, сделайте его явным.// плохоisFinite('2e3');// true// хорошоNumber.isFinite('2e3');// falseNumber.isFinite(parseInt('2e3',10));// true
30.1Ага.
functionfoo(){returntrue;}
- 30.2Нет, но серьёзно:
- Какой бы фреймворк вы не использовали, вы должны писать тесты!
- Стремитесь к тому, чтобы написать много маленьких чистых функций, и к тому, чтобы свести к минимуму места, где происходят мутации.
- Будьте осторожны со стабами (stubs) и моками (mocks) — они могут сделать ваше тестирование хрупким.
- Мы в первую очередь советуем вам использовать
mochaиjestот Airbnb.tapeтакже иногда используется для небольших, отдельных модулей. - 100% покрытие тестами — это хорошая цель, к которой надо стремиться, даже если это не всегда практично.
- Всякий раз, когда вы исправляете ошибку,пишите регрессионный тест. Исправленная ошибка без регрессионного тестирования почти наверняка всплывёт в будущем.
- On Layout & Web Performance
- String vs Array Concat
- Try/Catch Cost In a Loop
- Bang Function
- jQuery Find vs Context, Selector
- innerHTML vs textContent for script text
- Long String Concatenation
- Are JavaScript functions like
map(),reduce(), andfilter()optimized for traversing arrays? - Загрузка...
Изучение ES6+
Почитайте это
Инструменты
- Линтеры
- Neutrino Preset -@neutrinojs/airbnb
Другие руководства
- Google JavaScript Style Guide
- Google JavaScript Style Guide (Old)
- jQuery Core Style Guidelines
- Principles of Writing Consistent, Idiomatic JavaScript
- StandardJS
Другие стили
- Naming this in nested functions - Christian Johansen
- Conditional Callbacks - Ross Allen
- Popular JavaScript Coding Conventions on GitHub - JeongHoon Byun
- Multiple var statements in JavaScript, not superfluous - Ben Alman
Дальнейшее чтение
- Understanding JavaScript Closures - Angus Croll
- Basic JavaScript for the impatient programmer - Dr. Axel Rauschmayer
- You Might Not Need jQuery - Zack Bloom & Adam Schwartz
- ES6 Features - Luke Hoban
- Frontend Guidelines - Benjamin De Cock
Книги
- #"https://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752" rel="nofollow">JavaScript Patterns - Stoyan Stefanov
- Pro JavaScript Design Patterns - Ross Harmes and Dustin Diaz
- High Performance Web Sites: Essential Knowledge for Front-End Engineers - Steve Souders
- Maintainable JavaScript - Nicholas C. Zakas
- JavaScript Web Applications - Alex MacCaw
- Pro JavaScript Techniques - John Resig
- Smashing Node.js: JavaScript Everywhere - Guillermo Rauch
- Secrets of the JavaScript Ninja - John Resig and Bear Bibeault
- Human JavaScript - Henrik Joreteg
- Superhero.js - Kim Joar Bekkelund, Mads Mobæk, & Olav Bjorkoy
- JSBooks - Julien Bouquillon
- Third Party JavaScript - Ben Vinegar and Anton Kovalyov
- Effective #"https://eloquentjavascript.net/" rel="nofollow">Eloquent JavaScript - Marijn Haverbeke
- You Don’t Know JS: ES6 & Beyond - Kyle Simpson
Блоги
- JavaScript Weekly
- JavaScript, JavaScript...
- Bocoup Weblog
- Adequately Good
- NCZOnline
- Perfection Kills
- Ben Alman
- Dmitry Baranovskiy
- nettuts
Подкасты
Это список организаций, которые используют данное руководство. Отправьте нам пулреквест, и мы добавим вас в этот список.
- 123erfasst:123erfasst/javascript
- 4Catalyzer:4Catalyzer/javascript
- Aan Zee:AanZee/javascript
- Airbnb:airbnb/javascript
- AloPeyk:AloPeyk
- AltSchool:AltSchool/javascript
- Apartmint:apartmint/javascript
- Ascribe:ascribe/javascript
- Avant:avantcredit/javascript
- Axept:axept/javascript
- Billabong:billabong/javascript
- Bisk:bisk
- Bonhomme:bonhommeparis/javascript
- Brainshark:brainshark/javascript
- CaseNine:CaseNine/javascript
- Cerner:Cerner
- Chartboost:ChartBoost/javascript-style-guide
- Coeur d'Alene Tribe:www.cdatribe-nsn.gov
- ComparaOnline:comparaonline/javascript
- Compass Learning:compasslearning/javascript-style-guide
- DailyMotion:dailymotion/javascript
- DoSomething:DoSomething/eslint-config
- Digitpaintdigitpaint/javascript
- Drupal:www.drupal.org
- Ecosia:ecosia/javascript
- Evernote:evernote/javascript-style-guide
- Evolution Gaming:evolution-gaming/javascript
- EvozonJs:evozonjs/javascript
- ExactTarget:ExactTarget/javascript
- Flexberry:Flexberry/javascript-style-guide
- Gawker Media:gawkermedia
- General Electric:GeneralElectric/javascript
- Generation Tux:GenerationTux/javascript
- GoodData:gooddata/gdc-js-style
- GreenChef:greenchef/javascript
- Grooveshark:grooveshark/javascript
- Grupo-Abraxas:Grupo-Abraxas/javascript
- Happeo:happeo/javascript
- Honey:honeyscience/javascript
- How About We:howaboutwe/javascript
- HubSpot:HubSpot/javascript
- Hyper:hyperoslo/javascript-playbook
- InterCity Group:intercitygroup/javascript-style-guide
- Jam3:Jam3/Javascript-Code-Conventions
- JSSolutions:JSSolutions/javascript
- Kaplan Komputing:kaplankomputing/javascript
- KickorStick:kickorstick
- Kinetica Solutions:kinetica/javascript
- LEINWAND:LEINWAND/javascript
- Lonely Planet:lonelyplanet/javascript
- M2GEN:M2GEN/javascript
- Mighty Spring:mightyspring/javascript
- MinnPost:MinnPost/javascript
- MitocGroup:MitocGroup/javascript
- Muber:muber
- National Geographic:natgeo
- NullDev:NullDevCo/JavaScript-Styleguide
- Nulogy:nulogy/javascript
- Orange Hill Development:orangehill/javascript
- Orion Health:orionhealth/javascript
- OutBoxSoft:OutBoxSoft/javascript
- Peerby:Peerby/javascript
- Pier 1:Pier1/javascript
- Qotto:Qotto/javascript-style-guide
- React:facebook.github.io/react/contributing/how-to-contribute.html#style-guide
- REI:reidev/js-style-guide
- Ripple:ripple/javascript-style-guide
- Sainsbury’s Supermarkets:jsainsburyplc
- Shutterfly:shutterfly/javascript
- Sourcetoad:sourcetoad/javascript
- Springload:springload
- StratoDem Analytics:stratodem/javascript
- SteelKiwi Development:steelkiwi/javascript
- StudentSphere:studentsphere/javascript
- SwoopApp:swoopapp/javascript
- SysGarage:sysgarage/javascript-style-guide
- Syzygy Warsaw:syzygypl/javascript
- Target:target/javascript
- Terra:terra
- TheLadders:TheLadders/javascript
- The Nerdery:thenerdery/javascript-standards
- Tomify:tomprats
- Traitify:traitify/eslint-config-traitify
- T4R Technology:T4R-Technology/javascript
- UrbanSim:urbansim
- VoxFeed:VoxFeed/javascript-style-guide
- WeBox Studio:weboxstudio/javascript
- Weggo:Weggo/javascript
- Zillow:zillow/javascript
- ZocDoc:ZocDoc/javascript
Это руководство также переведено на другие языки:
Бразильский вариант португальского языка:armoucar/javascript-style-guide
Болгарский:borislavvv/javascript
Каталонский:fpmweb/javascript-style-guide
Китайский (Упрощённый):lin-123/javascript
Китайский (Традиционный):jigsawye/javascript
Французский:nmussy/javascript-style-guide
Немецкий:timofurrer/javascript-style-guide
Итальянский:sinkswim/javascript-style-guide
Японский:mitsuruog/javascript-style-guide
Корейский:ParkSB/javascript-style-guide
Русский:leonidlebedev/javascript-airbnb
Испанский:paolocarrasco/javascript-style-guide
Тайский:lvarayut/javascript-style-guide
Турецкий:eraycetinay/javascript
Украинский:ivanzusko/javascript
Вьетнамский:dangkyokhoang/javascript-style-guide
- Найдите их наgitter.
(The MIT License)
Copyright (c) 2012 Airbnb
Permission is hereby granted, free of charge, to any person obtaininga copy of this software and associated documentation files (the'Software'), to deal in the Software without restriction, includingwithout limitation the rights to use, copy, modify, merge, publish,distribute, sublicense, and/or sell copies of the Software, and topermit persons to whom the Software is furnished to do so, subject tothe following conditions:
The above copyright notice and this permission notice shall beincluded in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OFMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANYCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THESOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Мы рекомендуем вам сделать форк этого руководства и изменить его правила под стиль вашей команды. Ниже вы можете перечислить свои изменения в руководстве. Это позволит вам обновлять его время от времени, не сталкиваясь с конфликтами слияний.
About
Перевод «JavaScript Style Guide» от Airbnb
Topics
Resources
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Releases
Packages0
Uh oh!
There was an error while loading.Please reload this page.
Contributors8
Uh oh!
There was an error while loading.Please reload this page.