Skip to content

Repository files navigation

Стиль написання JavaScript від компанії Airbnb

Найбільш обгрунтований підхід до JavaScript

DownloadsDownloadsGitter

Інші керівництва по стилю

Зміст

  1. Типи
  2. Посилання
  3. Об'єкти
  4. Масиви
  5. Деструктурування
  6. Рядки
  7. Функції
  8. Arrow-функції
  9. Класи та Конструктори
  10. Модулі
  11. Ітератори та Генератори
  12. Властивості
  13. Змінні
  14. Підняття (Hoisting)
  15. Оператори порівняння і рівності
  16. Блоки
  17. Коментарі
  18. Пробіли
  19. Коми
  20. Крапка з комою
  21. Приведення типів та Примушення (Coercion)
  22. Угоди про іменування
  23. Аксессори
  24. Події
  25. jQuery
  26. ECMAScript 5 сумісність
  27. ECMAScript 6+ (ES 2015+) стилі
  28. Тестування
  29. Продуктивність
  30. Ресурси
  31. В реальному Світі
  32. Переклад
  33. Керівництво зі стилю написання JavaScript
  34. Поговоріть з нами про JavaScript
  35. Автори
  36. License

Типи

  • 1.1Примітиви: Коли ви отримуєте доступ до примітиву, ви працюєте напряму з його значенням.

    • string
    • number
    • boolean
    • null
    • undefined
    constfoo=1;letbar=foo;bar=9;console.log(foo,bar);// => 1, 9

  • 1.2Складні типи: Коли ви отримуєте доступ до складного типу, ви працюєте з посиланням на його значення.

    • object
    • array
    • function
    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 jscs: disallowVar

    Чому? let має блочну область видимості, на відміну від var, область видимості котрого обмежена функцією.

    // поганоvarcount=1;if(true){count+=1;}// добре, використовуйте let.letcount=1;if(true){count+=1;}

  • 2.3 Зауважте, що і let і const мають блочну область видимості.

    // const та let існують лише в межах блоку, в якому вони були визначені.{leta=1;constb=1;}console.log(a);// ReferenceErrorconsole.log(b);// ReferenceError

⬆ вверх

Об'єкти

  • 3.1 Використовуйте літерали (фігурні скобки) для створення нового об'єкта. Не використовуйте для створення нового об'єкта конструктор new Object. 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 jscs: requireEnhancedObjectLiterals

    // поганоconstatom={value: 1,addValue: function(value){returnatom.value+value;},};// добреconstatom={value: 1,addValue(value){returnatom.value+value;},};

  • 3.4 Використовуйте скорочення значення властивості. eslint: object-shorthand jscs: requireEnhancedObjectLiterals

    Чому? Так менше писати і більш зрозуміло.

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

Чому? В загальному, ми вважаємо, що так суб'єктивно легше читати. Це покращує підсвітку синтаксису, а також більш легко оптимізується багатьма JS двигунами.

// поганоconstbad={'foo': 3,'bar': 4,'data-blah': 5,};// добреconstgood={foo: 3,bar: 4,'data-blah': 5,};

  • 3.7 Не використовуйте напряму методи Object.prototype, такі як hasOwnProperty, propertyIsEnumerable, і isPrototypeOf.

Чому? Ці методи можуть бути переоприділені на поточному об'єкті, наприклад: { hasOwnProperty: false }, або ж поточний об'єкт може не мати прототипа (Object.create(null)).

// поганоconsole.log(object.hasOwnProperty(key));// добреconsole.log(Object.prototype.hasOwnProperty.call(object,key));// найкращеconsthas=Object.prototype.hasOwnProperty;// закешовуємо результати пошуку у скоупі модуля./* або */importhasfrom'has';console.log(has.call(object,key));

  • 3.8 Віддавайте перевагу spread оператору над Object.assign для дрібного копіювання об'єктів. Використовуйте rest оператор для отримання нового об'єкта з певними відсутніми властивостями.
// дуже погано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 Використовуйте ...( spreads ) оператор масива для копіювання масивів.

    // погано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);

  • 4.5 Використовуйте оператор return у функціях зворотнього виклику методу масива. Це нормально не робити повернення, якщо тіло функції складається з одного визначення згідно з 8.2. eslint: array-callback-return

    // добре[1,2,3].map((x)=>{consty=x+1;returnx*y;});// добре[1,2,3].map(x=>x+1);// поганоconstflat={};[[0,1],[2,3],[4,5]].reduce((memo,item,index)=>{constflatten=memo.concat(item);flat[index]=flatten;});// добреconstflat={};[[0,1],[2,3],[4,5]].reduce((memo,item,index)=>{constflatten=memo.concat(item);flat[index]=flatten;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;});

⬆ вверх

Деструктурування

  • 5.1 Використовуйте деструктурування об'єкта, коли отримуєте доступ і використовуєте декілька властивостей об'єкта. jscs: requireObjectDestructuring

    Чому? Деструктурування вберігає вас від створення тимчасових посиланнь на ті властивості.

    // погано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 Використовуйте деструктурування масивів. jscs: requireArrayDestructuring

    constarr=[1,2,3,4];// поганоconstfirst=arr[0];constsecond=arr[1];// добреconst[first,second]=arr;

  • 5.3 Використовуйте деструктурування об'єкта, а не масива, для декількох повертаємих значеннь . jscs: disallowArrayDestructuringReturn

    Чому? Ви зможете з часом додати нові властивості або змінити послідовність речей не порушуючи розташування викликів.

    // погано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 jscs: validateQuoteMarks

    // погано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 jscs: requireTemplateStrings

    Чому? Рядкові шаблони дають читабельність, короткий синтаксис з переносом нових ліній та функціями інтерполяції рядка.

    // погано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.4 Ніколи не використовуйте eval() на рядку, це відкриває дуже багато вразливостей.

  • 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 jscs: disallowFunctionDeclarations

    Чому? Функціональні оголошення хойстяться (вспливають уверх), це означає, що дуже легко послатися на функцію до того, як вона оголошена у файлі. Це шкодить читаємості та підтримуємості. Якщо вам здається, що визначення функції досить велике чи воно ускладнює розуміння іншої частини файлу, то, можливо, прийшов час, щоб виокремити це в окремий модуль! Не забувайте іменувати вирази - анонімні функції можуть ускладнити локалізацію проблеми у стеку викликів. (Discussion)

    // поганоconstfoo=function(){};// поганоfunctionfoo(){}// добреconstfoo=functionbar(){};

  • 7.2 Огортайте негайно виконувані функціональні вирази (НВФВ) у дужки. eslint: wrap-iife jscs: requireParenthesesAroundIIFE

    Чому? Негайно виконуваний функціональний вираз являє собою єдиний блок - огортання обох, і його і його виклику чітко це показує. Варто зауважити, що у світі де модулі повсюди, вам майже ніколи не потрібен НВФВ.

    // Негайно виконуваний функціональний вираз (НВФВ)(function(){console.log('Welcome to the Internet. Please follow me.');}());

  • 7.3 Ніколи не оголошуйте функцію у нефункціональному блоці(if, while, etc). Натомість, призначте функцію змінній. Браузери дозволять вам це зробити, але всі вони інтерпретують це по-різному, що є поганими новинами. eslint: no-loop-func

  • 7.4Увага: ECMA-262 визначає block як список визначень. Оголошення функції не є визначенням. Read ECMA-262's note on this issue.

    // поганоif(currentUser){functiontest(){console.log('Nope.');}}// добреlettest;if(currentUser){test=()=>{console.log('Yup.');};}

  • 7.5 Ніколи не називайте параметр як arguments. Це матиме пріоритет над arguments об'єкта, який надається області видимості кожної функції.

    // поганоfunctionnope(name,options,arguments){// ...щось відбувається...}// добреfunctionyup(name,options,args){// ...щось відбувається...}

  • 7.6 Ніколи не використовуйте arguments, краще натомість використовуйте rest синтаксис (...). eslint: prefer-rest-params

    Чому? ... оператор явно зазначає, що ви хочете щось витягти. Крім того, rest аргументи являються реальним масивом, а не масивоподібністю, як arguments.

    // поганоfunctionconcatenateAll(){constargs=Array.prototype.slice.call(arguments);returnargs.join('');}// добреfunctionconcatenateAll(...args){returnargs.join('');}

  • 7.7 Використовуйте синтаксис "параметру за замовчуванням", а не мутуйте аргументи функції.

    // насправді поганоfunctionhandleThings(opts){// Ні! Ми не повинні мутувати аргументи функції.// Двічі погано: якщо `opts` є неправдивим(`falsy` - прим. прекладача), то воно так і буде задано об'єкту. Це, звісно, може бути тим, що// вам саме потрібно, але це може призвести до тонких багів.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 Завжди зазначайте параметри за замовчуванням останніми.

    // погано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

    Чому? Перепризначення параметрів може призвести до неочікуваної поведінки, особливо, при доступі до об'єкту аргументів. Це також може викликати оптимізаційні проблеми, особливо у V8.

    // поганоfunctionf1(a){a=1;}functionf2(a){if(!a){a=1;}}// добреfunctionf3(a){constb=a||1;}functionf4(a=1){}

  • 7.14 Віддавайте перевагу використанню ... (оператор spread) при виклику функцій зі змінним числом параметрів . 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,08,05]));// добреnewDate(...[2016,08,05]);

  • 7.15 Функції з кількома сигнатурами, чи викликами, повинні бути з відступами, так само як і будь-який інший список у кілька рядків у цьому керівництві: з кожним елементом на своєму рядку, з комою у кінці кожного рядка.

    // поганоfunctionfoo(bar,baz,quux){// тіло функції}// добреfunctionfoo(bar,baz,quux,){// тіло функції}// поганоconsole.log(foo,bar,baz);// добреconsole.log(foo,bar,baz,);

⬆ вверх

Arrow-функції

  • 8.1 Коли вам потрібно використати функціональний вираз (так само якщо потрібно передати анонімну функцію) - використовуйте позначення arrow-функції. eslint: prefer-arrow-callback, arrow-spacing jscs: requireArrowFunctions

    Чому? Це створює версію функції, яка виконується у контексті 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 jscs: disallowParenthesesAroundArrowParam, requireShorthandArrowFunctions

    Чому? Синтаксичний цукор. Це гарно читається, особливо коли кілька функцій формують послідовний ланцюжок.

    // погано[1,2,3].map(number=>{constnextNumber=number+1;`A string containing the ${nextNumber}.`;});// добре[1,2,3].map(number=>`A string containing the ${number}.`);// добре[1,2,3].map((number)=>{constnextNumber=number+1;return`A string containing the ${nextNumber}.`;});// добре[1,2,3].map((number,index)=>({[index]: number}));

  • 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 jscs: disallowParenthesesAroundArrowParam

    Чому? Менше візуального безладу.

    // погано[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(x=>{consty=x+1;returnx*y;});// добре[1,2,3].map((x)=>{consty=x+1;returnx*y;});

  • 8.5 Уникайте синтаксису arrow-функції (=>) з операторами порівняння (<=, >=), оскільки це може збити з пантелику. 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;};

⬆ вверх

Класи та Конструктори

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

⬆ вверх

Модулі

  • 10.1 Завжди віддавайте перевагу використанню (import/export) модуля, а не нестандартній модульній системі. Ви завжди можете сконвертувати(transpile) до вашої улюбленої модульної системи.

    Чому? Модулі - це майбутнє, тож давайте використовувати майбутнє вже зараз.

    // поганоconstAirbnbStyleGuide=require('./AirbnbStyleGuide');module.exports=AirbnbStyleGuide.es6;// нормальноimportAirbnbStyleGuidefrom'./AirbnbStyleGuide';exportdefaultAirbnbStyleGuide.es6;// найкращеimport{es6}from'./AirbnbStyleGuide';exportdefaultes6;

  • 10.2 Ніколи не вживайте непередбачувані імпорти.

    Чому? Це гарантує, що у вас по замовчуванню експортується лише один модуль.

    // поганоimport*asAirbnbStyleGuidefrom'./AirbnbStyleGuide';// добреimportAirbnbStyleGuidefrom'./AirbnbStyleGuide';

  • 10.3 І не експортуйте напряму з імпорту.

    Чому? Не дивлячись на те, що одна строка це досить коротко, мати один чіткий шлях для імпорта і один чіткий шлях для експорта робить речі більш зрозумілими.

    // погано// filename es6.jsexport{es6asdefault}from'./AirbnbStyleGuide';// добре// filename es6.jsimport{es6}from'./AirbnbStyleGuide';exportdefaultes6;

  • 10.4 Імпортуйте з одного місця лише раз. eslint: no-duplicate-imports

    Чому? Коли є кілька рядків, які імпортують з одного шляху - це ускладнює підтримку коду.

    // поганоimportfoofrom'foo';// … some other imports … //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 У модулі з єдиним експортом віддавайте превагу експорту за замовчуванням (default), а не іменованому експорту. eslint: import/prefer-default-export

    // поганоexportfunctionfoo(){}// добреexportdefaultfunctionfoo(){}

  • 10.7 Зазначайте всі import визначення над не імпортами. eslint: import/first

    Чому? Оскільки importи вспливають вгору, то тримати їх зверху убезпечує від неочікуваної поведінки.

    // поганоimportfoofrom'foo';foo.init();importbarfrom'bar';// добреimportfoofrom'foo';importbarfrom'bar';foo.init();

  • 10.8 Імпорти у кілька рядків мають мати такі самі відступи як і масиви чи об'єктні літерали.

    Чому? Фігурні дужки дотримуються тих самих правил, як і кожен блок з фігурними дужками у цьому керівництві. Те саме стосується і ком у кінці кожного рядка в середині блоку.

    // поганоimport{longNameA,longNameB,longNameC,longNameD,longNameE}from'path';// добреimport{longNameA,longNameB,longNameC,longNameD,longNameE,}from'path';

  • 10.9 Забороняти Webpack loader синтаксис у оголошенні модульного імпорту. eslint: import/no-webpack-loader-syntax

    Чому? TODO: COMPLETE Since using Webpack syntax in the imports couples the code to a module bundler. Prefer using the loader syntax in webpack.config.js.

    // поганоimportfooSassfrom'css!sass!foo.scss';importbarCssfrom'style!css!bar.css';// добреimportfooSassfrom'foo.scss';importbarCssfrom'bar.css';

⬆ вверх

Ітератори та генератори

  • 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 Якщо вам потрібно використати генератори, або якщо ви вирішили не скористатись нашою порадою our advice, переконайтесь, що сигнатура функції має правильні відступи. 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-notation jscs: requireDotNotation

    constluke={jedi: true,age: 28,};// поганоconstisJedi=luke['jedi'];// добреconstisJedi=luke.jedi;

  • 12.2 Використовуйте квадратні дужки [] при доступі до властивостей через змінні.

    constluke={jedi: true,age: 28,};functiongetProp(prop){returnluke[prop];}constisJedi=getProp('jedi');

⬆ вверх

Змінні

  • 13.1 Завжди використовуйте const для оголошення змінних. Недотримання цієї вимоги призведе до глобальних змінних. Ми хочемо уникнути забруднення глобального простору імен. Капітан Планета застерігає нас від цього. eslint: no-undefprefer-const

    // поганоsuperPower=newSuperPower();// добреconstsuperPower=newSuperPower();

  • 13.2 Використовуйте по одному const для кожної змінної. eslint: one-var jscs: disallowMultipleVarDecl

    Чому? Так легше оголошувати змінні таким чином, що вам не потрібно буде хвилюватись, що ви випадково переплутаєте в кінці рядка ; з ,. Ви також можете пройти через кожне оголошення змінної за допомогою дебагера, замість того, щоб перестрибнути через всі оголошення змінних одразу.

    // поганоconstitems=getItems(),goSportsTeam=true,dragonball='z';// погано// (порівняйте з верхнім і спробуйте знайти помилку)constitems=getItems(),goSportsTeam=true;dragonball='z';// добреconstitems=getItems();constgoSportsTeam=true;constdragonball='z';

  • 13.3 Спочатку групуйте всі ваші const, а потім вже групуйте всі lets.

    Чому? Це дуже зручно у випадку, коли в подальшому вам знадобиться оголосити зміну в залежності від вже оголошених змінних.

    // погано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 Не поєднуйте в ланцюжки присвоєння змінних.

    Чому? Поєднання змінних у ланцюжки створює неявні глобальні змінні.

    // погано(functionexample(){// JavaScript інтерпретує це як// let a = ( b = ( c = 1 ) );// Ключове слово let застосовується до змінної a; змінні b та c стають// глобальними змінними.leta=b=c=1;}());console.log(a);// undefinedconsole.log(b);// 1console.log(c);// 1// добре(functionexample(){leta=1;letb=a;letc=a;}());console.log(a);// undefinedconsole.log(b);// undefinedconsole.log(c);// undefined// Те ж саме стосується і `const`

  • 13.6 Уникайте використання унарних збільшеннь та зменшеннь (++, --). eslint no-plusplus

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

    // поганоletarray=[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++;}}// добреletarray=[1,2,3];letnum=1;num+=1;num-=1;constsum=array.reduce((a,b)=>a+b,0);consttruthyCount=array.filter(Boolean).length;

⬆ вверх

Підняття (Hoisting)

  • 14.1 Оголошені змінні, за допомогою ключового слова var, піднімаються вгору обсласті видимості функції, в той час як привласнені їм значення - ні. Змінні, оголошені за допомогою const та let отримали нову концепцію - Тимчасові Мертві Зони (ТМЗ). Важливо знати, чому використовувати 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 is not a functionvaranonymous=function(){console.log('anonymous function expression');};}

  • 14.3 Іменовані функціональні вирази піднімають ім'я змінної, але не ім'я функції чи тіло функції.

    functionexample(){console.log(named);// => undefinednamed();// => TypeError named is not a functionsuperPower();// => ReferenceError superPower is not definedvarnamed=functionsuperPower(){console.log('Flying');};}// це також стосується і випадку,// коли ім'я функції співпадає з іменем змінної.functionexample(){console.log(named);// => undefinednamed();// => TypeError named is not a functionvarnamed=functionnamed(){console.log('named');}}

  • 14.4 Функціональне оголошення піднімає ім'я і тіло функції.

    functionexample(){superPower();// => FlyingfunctionsuperPower(){console.log('Flying');}}
  • За більш детальною інформацією звертайтесь до JavaScript Scoping & Hoisting автор Ben Cherry.

⬆ вверх

Оператори порівняння та рівності

  • 15.1 Використовуйте === та !== а не == і не !=. eslint: eqeqeq

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

    • Objects оцінюється як true
    • Undefined оцінюється як false
    • Null оцінюється як false
    • Booleans оцінюються як the value of the boolean
    • Numbers оцінюється як false, якщо +0, -0, or NaN, в усіх інших випадках як true
    • Strings оцінюється як false якщо рядок порожній '', в усіх інших випадках як true
    if([0]&&[]){// true// масив (навіть якщо він порожній) - це об'єкт, а об'єкт завжди оцінюється як true}

  • 15.3 Використовуйте скорочення для логічних значеннь, але явно зазначайте, коли порівнюєте рядки та числа.

    // поганоif(isValid===true){// ...stuff...}// добреif(isValid){// ...stuff...}// поганоif(name){// ...stuff...}// добреif(name!==''){// ...stuff...}// поганоif(collection.length){// ...stuff...}// добреif(collection.length>0){// ...stuff...}

  • 15.5 Використовуйте дужки для створення блоків case та default що містять лексичні декларації (e.g. let, const, function, та class).

Чому? Лексичні проголошення видимі у всьому switch блоці, але вони ініціалізуються лише тоді, коли привласнюються, а це стається лише тоді, коли спрацьювує case. Це спричиняє проблеми, коли кілька case випадків намагаються визначити одну й ту саму річ.

eslint rules: no-case-declarations.

```javascript
// погано
switch (foo) {
case 1:
let x = 1;
break;
case 2:
const y = 2;
break;
case 3:
function f() {}
break;
default:
class C {}
}
// добре
switch (foo) {
case 1: {
let x = 1;
break;
}
case 2: {
const y = 2;
break;
}
case 3: {
function f() {}
break;
}
case 4:
bar();
break;
default: {
class C {}
}
}
```

  • 15.6 Тернарні оператори не повинні вкладатись будь яким чином, а мають бути записані в один рядок.

    eslint rules: no-nested-ternary.

    // поганоconstfoo=maybe1>maybe2
    ? "bar"
    : value1>value2 ? "baz" : null;// кращеconstmaybeNull=value1>value2 ? 'baz' : null;constfoo=maybe1>maybe2
    ? 'bar'
    : maybeNull;// найкращеconstmaybeNull=value1>value2 ? 'baz' : null;constfoo=maybe1>maybe2 ? 'bar' : maybeNull;

  • 15.7 Уникайте непотрібних тернарних записів.

    eslint rules: no-unneeded-ternary.

    // поганоconstfoo=a ? a : b;constbar=c ? true : false;constbaz=c ? false : true;// добреconstfoo=a||b;constbar=!!c;constbaz=!c;

⬆ вверх

Блоки

  • 16.1 Використовуйте дужки в усіх блоках які записуються у кілька рядків.

    // поганоif(test)returnfalse;// добреif(test)returnfalse;// добреif(test){returnfalse;}// поганоfunctionfoo(){returnfalse;}// добреfunctionbar(){returnfalse;}

  • 16.2 Якщо ви використовуєте блоки у кілька рядків з if та else, то ставте else на тому самому рядку, що і закриваюча дужка if блоку. eslint: brace-style jscs: disallowNewlineBeforeBlockStatements

    // поганоif(test){thing1();thing2();}else{thing3();}// добреif(test){thing1();thing2();}else{thing3();}

⬆ вверх

Коментарі

  • 17.1 Використовуйте /** ... */ для коментарів у кілька рядків.

    // погано// make() returns a new element// based on the passed in tag name//// @param {String} tag// @return {Element} elementfunctionmake(tag){// ...stuff...returnelement;}// добре/** * make() returns a new element * based on the passed-in tag name */functionmake(tag){// ...stuff...returnelement;}

  • 17.2 Використовуйте // для коментарів в один рядок. Ставте однорядковий коментар на новий рядок одразу над суб'єктом, до якого відноситься цей коментар. Ставте порожній рядок перед коментарем, якщо тільки це не перший рядок блоку.

    // поганоconstactive=true;// is current tab// добре// is current tabconstactive=true;// поганоfunctiongetType(){console.log('fetching type...');// set the default type to 'no type'consttype=this._type||'no type';returntype;}// добреfunctiongetType(){console.log('fetching type...');// set the default type to 'no type'consttype=this._type||'no type';returntype;}// також добреfunctiongetType(){// set the default type to 'no type'consttype=this._type||'no type';returntype;}
  • 17.3 Починайте всі коментарі з пробілу для більше легкого читання. eslint: spaced-comment

    // погано//is current tabconstactive=true;// добре// is current tabconstactive=true;// погано/** *make() returns a new element *based on the passed-in tag name */functionmake(tag){// ...stuff...returnelement;}// добре/** * make() returns a new element * based on the passed-in tag name */functionmake(tag){// ...stuff...returnelement;}

  • 17.4 Починати ваш коментар зі слів FIXME чи TODO добре, оскільки це допомагає іншим розробникам швидко розуміти, чи ви відзначаєте проблемне місце в коді, яке треба переглянути, чи ви пропонуєте вирішення проблеми, яке має бути запроваджене. Вони відрізняються від звичайних коментарів, оскільки вони вимагають дії. Дія може бути FIXME: -- потрібно в цьому розібратись і виправити or TODO: -- потрібно запровадити.

  • 17.5 Використовуйте // FIXME: для описання проблеми.

    classCalculatorextendsAbacus{constructor(){super();// FIXME: shouldn't use a global heretotal=0;}}

  • 17.6 Використовуйте // TODO: для описання способів вирішення проблеми.

    classCalculatorextendsAbacus{constructor(){super();// TODO: total should be configurable by an options paramthis.total=0;}}

⬆ вверх

Пробіли

  • 18.1 Використовуйте табуляцію у 2 пробіли. eslint: indent jscs: validateIndentation

    // поганоfunctionfoo(){∙∙∙∙constname;}// поганоfunctionbar(){∙constname;}// добреfunctionbaz(){∙∙constname;}

  • 18.2 Ставте 1 пробіл перед ведучою фігурною дужкою. eslint: space-before-blocks jscs: requireSpaceBeforeBlockStatements

    // погано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',});

  • 18.3 Ставте 1 пробіл перед відкриваючою дужкою у умовах (if, while і т.д.). Не ставте пробіли між списком аргументів та іменем функції, та між іменем функції та викликами функції і проголошеннями. eslint: keyword-spacing jscs: requireSpaceAfterKeywords

    // поганоif(isJedi){fight();}// добреif(isJedi){fight();}// поганоfunctionfight(){console.log('Swooosh!');}// добреfunctionfight(){console.log('Swooosh!');}

  • 18.5 Лишайте символ нового рядку у кінці файлу. eslint: eol-last

    // поганоimport{es6}from'./AirbnbStyleGuide';// ...exportdefaultes6;
    // поганоimport{es6}from'./AirbnbStyleGuide';// ...exportdefaultes6;
    // добреimport{es6}from'./AirbnbStyleGuide';// ...exportdefaultes6;

  • 18.6 Використовуйте відступи, коли робите ланцюжки методів (більш ніж два методи у ланцюгу). Використовуйте ведучу крапку, яка підкреслює, що на новій лінії відбувається виклик методу, а не нове ствердження. 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);

  • 18.7 Лишайте порожній рядок після блоків і перед наступним ствердженням. jscs: requirePaddingNewLinesAfterBlocks

    // поганоif(foo){returnbar;}returnbaz;// добреif(foo){returnbar;}returnbaz;// поганоconstobj={foo(){},bar(){},};returnobj;// добреconstobj={foo(){},bar(){},};returnobj;// поганоconstarr=[functionfoo(){},functionbar(){},];returnarr;// добреconstarr=[functionfoo(){},functionbar(){},];returnarr;

  • 18.8 Не насичуйте ваші блоки порожніми лініями. eslint: padded-blocks jscs: disallowPaddingNewlinesInBlocks

    // погано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);}

  • 18.9 Не додавайте пробілів в середині дужок. eslint: space-in-parens jscs: disallowSpacesInsideParentheses

    // поганоfunctionbar(foo){returnfoo;}// добреfunctionbar(foo){returnfoo;}// поганоif(foo){console.log(foo);}// добреif(foo){console.log(foo);}

  • 18.12 Уникайте ліній коду, що довші за 100 символів (включаючи пробіли). Примітка: зазначені тут довгі рядки не підпадають під це правило і не повинні розбиватись. eslint: max-len jscs: maximumLineLength

    Чому? Це забезпечує читаємість та підтримку.

    // погано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.1 Направляючі коми: Ні. eslint: comma-style jscs: requireCommaBeforeLineBreak

    // погано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',};

  • 19.2 Додаткова кома в кінці рядку: Так. eslint: comma-dangle jscs: requireTrailingComma

    Чому? Це веде до чистіших відмінностей у git. Також, транспайелри, такі як 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){// does nothing}// добреfunctioncreateHero(firstName,lastName,inventorOf,){// does nothing}// добре (зауважте, що кома не повинна з'являтись після "rest" елементу)functioncreateHero(firstName,lastName,inventorOf,
    ...heroArgs){// does nothing}// поганоcreateHero(firstName,lastName,inventorOf);// добреcreateHero(firstName,lastName,inventorOf,);// добре (зауважте, що кома не повинна з'являтись після "rest" елементу)createHero(firstName,lastName,inventorOf,
    ...heroArgs)

⬆ вверх

Крапка з комою

  • 20.1Так. eslint: semi jscs: requireSemicolons

    // погано(function(){constname='Skywalker'returnname})()// добре(function(){constname='Skywalker';returnname;}());// добре, але застаріло (захист, щоб функція не перетворювалась на аргумент, коли об'єднуються два файли за допомогою IIFEs(негайно виконуваний функціональний вираз (НВФВ)));(()=>{constname='Skywalker';returnname;}());

    Прочитати більше.

⬆ вверх

Приведення типів та Примушення

  • 21.1 Виконуйте примусове приведення типу на початку ствердження.

  • 21.2 Рядки:

    // => this.reviewScore = 9;// поганоconsttotalScore=this.reviewScore+'';// викликає this.reviewScore.valueOf()// поганоconsttotalScore=this.reviewScore.toString();// не гарантовано, що повернеться рядок// добреconsttotalScore=String(this.reviewScore);

  • 21.3 Цифри: Використовуйте Number для приведення типу та parseInt завжди з десятичною для синтаксичного аналізу рядків. eslint: radix

    constinputValue='4';// поганоconstval=newNumber(inputValue);// поганоconstval=+inputValue;// поганоconstval=inputValue>>0;// поганоconstval=parseInt(inputValue);// добреconstval=Number(inputValue);// добреconstval=parseInt(inputValue,10);

  • 21.4 Якщо, з якоїсь причини, ви робите щось дике і parseInt являється слабкою ланкою і вам потрібно використати бітову операцію заради ефективності, залиште коментар, який пояснює навіщо і що ви робите.

    // добре/** * parseInt сповільнював код. * Застосування бітової операції щодо рядка для примусового приведення до * Number робить код набагато швидшим. */constval=inputValue>>0;

  • 21.5Зауважте: Будьте обачні при використанні бітових операцій. Цифри представленні як 64-бітні значення, але бітові операції завжди повертають 32-bit ціле число (джерело). Бітова операція може призвести до непердбачуваної поведінки для цілик значеннь, більших ніж 32-біта. Обговорення. Найбільшим виявленим 32-бітним цілим числом є 2,147,483,647:

    2147483647>>0//=> 21474836472147483648>>0//=> -21474836482147483649>>0//=> -2147483647

  • 21.6 Булеві значення:

    constage=0;// поганоconsthasAge=newBoolean(age);// добреconsthasAge=Boolean(age);// bestconsthasAge=!!age;

⬆ вверх

Угоди про іменування

  • 22.1 Уникайте імен в одну літеру. Нехай ваші імена будуть описовими. eslint: id-length

    // поганоfunctionq(){// ...stuff...}// добреfunctionquery(){// ..stuff..}

  • 22.2 Використовуйте camelCase коли називаєте об'єкти, функції і екземпляри. eslint: camelcase jscs: requireCamelCaseOrUpperCaseIdentifiers

    // поганоconstOBJEcttsssss={};constthis_is_my_object={};functionc(){}// добреconstthisIsMyObject={};functionthisIsMyFunction(){}

  • 22.3 Використовуйте PascalCase лише коли називаєте конструктори чи класи. eslint: new-cap jscs: requireCapitalizedConstructors

    // поганоfunctionuser(options){this.name=options.name;}constbad=newuser({name: 'nope',});// добреclassUser{constructor(options){this.name=options.name;}}constgood=newUser({name: 'yup',});

  • 22.4 Не використовуйте завершальних чи лідуючих нижніх підкресленнь(underscores). eslint: no-underscore-dangle jscs: disallowDanglingUnderscores

    Чому? В JavaScript немає поняття приватності властивостей чи методів. Хоча, лідуюче нижнє підкреслення і прийнято використовувати для позначення "приватності", насправді, ці властивості всі публічні, і тому являються частиною вашого публічного API. Такий підхід може ввести розробниців в оману, що зміна не буде критичною, чи що не потрібні тести. tl;dr: якщо ви хочете зробити щось "приватним", воно не має бути видимим для сторонніх.

    // поганоthis.__firstName__='Panda';this.firstName_='Panda';this._firstName='Panda';// добреthis.firstName='Panda';

  • 22.5 Не зберігайте посиланнь на this. Використовуйте arrow-функції чи Function#bind. jscs: disallowNodeTypes

    // поганоfunctionfoo(){constself=this;returnfunction(){console.log(self);};}// поганоfunctionfoo(){constthat=this;returnfunction(){console.log(that);};}// добреfunctionfoo(){return()=>{console.log(this);};}

  • 22.6 Базове ім'я файлу має співпадати з експортом за замовчуванням.

    // файл 1 міститьclassCheckBox{// ...}exportdefaultCheckBox;// файл 2 міститьexportdefaultfunctionfortyTwo(){return42;}// файл 3 міститьexportdefaultfunctioninsideDirectory(){}// у якомусь іншому файлі// погано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"// ^ supports both insideDirectory.js and insideDirectory/index.js

  • 22.7 Використовуйте camelCase коли ви експортуєте за замовчуванням function. Ім'я файлу повинно співпадати з іменем функції.

    functionmakeStyleGuide(){}exportdefaultmakeStyleGuide;

  • 22.8 Використовуйте PascalCase коли ви експортуєте конструктор / клас / функціональну бібліотеку / чистий об'єкт.

    constAirbnbStyleGuide={es6: {}};exportdefaultAirbnbStyleGuide;

  • 22.9 Скорочення або абревіатури повинні завжди всі писатись або великими або маленькими літерами.

    Чому? Імена для зручності читання, а не для вдоволення комп'ютерного алгоритму.

    // поганоimportSmsContainerfrom'./containers/SmsContainer';// поганоconstHttpRequests=[// ...];// добреimportSMSContainerfrom'./containers/SMSContainer';// добреconstHTTPRequests=[// ...];// найкращеimportTextMessageContainerfrom'./containers/TextMessageContainer';// найкращеconstRequests=[// ...];

⬆ вверх

Аксессори

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

  • 23.2 Не використовуйте геттери/сеттери JavaScript оскільки вони викликають неочікуванні побічні ефекти і їх важко тестувати, підтримувати і аргументувати їхню необхідність. Натомість, якщо ви робити функцію доступу - використовуйте getVal() та setVal('hello').

    // поганоclassDragon{getage(){// ...}setage(value){// ...}}// добреclassDragon{getAge(){// ...}setAge(value){// ...}}

  • 23.3 Якщо властивість/метод являються boolean, використовуйте isVal() або hasVal().

    // поганоif(!dragon.age()){returnfalse;}// добреif(!dragon.hasAge()){returnfalse;}

  • 23.4 Це нормально створювати get() та set() функції, але будьте послідовні.

    classJedi{constructor(options={}){constlightsaber=options.lightsaber||'blue';this.set('lightsaber',lightsaber);}set(key,val){this[key]=val;}get(key){returnthis[key];}}

⬆ вверх

Події

  • 24.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});

⬆ вверх

jQuery

  • 25.1 Префіксуйте об'єкт jQuery знаком $. jscs: requireDollarBeforejQueryAssignment

    // поганоconstsidebar=$('.sidebar');// добреconst$sidebar=$('.sidebar');// добреconst$sidebarBtn=$('.sidebar-btn');

  • 25.2 Кешуйте результати пошуку jQuery.

    // поганоfunctionsetSidebar(){$('.sidebar').hide();// ...щось відбувається...$('.sidebar').css({'background-color': 'pink'});}// добреfunctionsetSidebar(){const$sidebar=$('.sidebar');$sidebar.hide();// ...щось відбувається...$sidebar.css({'background-color': 'pink'});}

  • 25.3 Для звернень до DOM використовуйте каскадність запиту $('.sidebar ul') або предок > нащадок $('.sidebar > ul'). jsPerf

  • 25.4 Використовуйте find з контекстними запитами jQuery об'єкта.

    // погано$('ul','.sidebar').hide();// погано$('.sidebar').find('ul').hide();// добре$('.sidebar ul').hide();// добре$('.sidebar > ul').hide();// добре$sidebar.find('ul').hide();

⬆ вверх

ECMAScript 5 сумісність

⬆ вверх

ECMAScript 6+ (ES 2015+) стилі

  • 27.1 Це колекція посилання на різні особливості ES6.
  1. Arrow Functions
  2. Класи та Конструктори
  3. Скорочення для методіва об'єкта
  4. Скорочення об'єкта
  5. Вираховані властивості об'єкта
  6. Строчні шаблони
  7. Destructuring
  8. Параметри за замовчуаванням
  9. Rest
  10. spreads оператор масива
  11. Let та Const
  12. Ітератори та Генератори
  13. Модулі

  • 27.2 Не використовуйте TC39 пропозиції які не знаходяться у стадії stage 3.

    Чому? Вони не завершені, і вони можуть бути змінені або повністю відмінені. Ми хочемо використовувати JavaScript, а пропозиції, покищо, ще не JavaScript.

⬆ вверх

Тестування

  • 28.1Так.

    functionfoo(){returntrue;}

  • 28.2Ні, але серйозно:
  • Який би тестувальний фреймфорк ви б не використовували - ви повинні писати тести!
  • Намагайтесь писати багато дрібних функцій та зводити до мінімуму місця, де відбуваються мутації.
  • Будьте обережними з stubs та mocks, оскільки вони можуть зробити ваші тести більш крихкими.
  • Ми в першу чергу використовуємо mocha у Airbnb. tape також час від часу використовується для маленьких, окремих модулів.
  • 100% покриття тестами - це гарна мета до якої варто прагнути, навіть якщо це не завжди практично.
  • Кожного разу, коли ви виправляєте помилку, пишіть тест регресії. Помилка виправлена без написання регресивного тесту майже точно виникне в майбутньому знову.

⬆ вверх

Продуктивність

⬆ вверх

Ресурси

Вивчення ES6

Прочитайте це

Інструменти

Інші керівництва

Інші стилі

Подальше читання

Книжки

Блоги

Подкасти

⬆ вверх

В реальному Світі

Це перелік організацій які використовують це керівництво. Надішліть нам pull request і ми додамо вас до цього списку.

⬆ вверх

Translation

This style guide is also available in other languages:

The JavaScript Style Guide Guide

Chat With Us About JavaScript

Contributors

License

(The MIT License)

Copyright (c) 2014-2016 Airbnb

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

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

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

⬆ вверх

Amendments

We encourage you to fork this guide and change the rules to fit your team's style guide. Below, you may list some amendments to the style guide. This allows you to periodically update your style guide without having to deal with merge conflicts.

};

About

Translation of Airbnb's JavaScript Style Guide

Resources

Stars

120 stars

Watchers

8 watching

Forks

Releases

Packages

Used by

Contributors

Languages