| Dec | JAN | Feb |
| 19 | ||
| 2020 | 2021 | 2022 |
COLLECTED BY
Formed in 2009, the Archive Team (not to be confused with the archive.org Archive-It Team) is a rogue archivist collective dedicated to saving copies of rapidly dying or deleted websites for the sake of history and digital heritage. The group is 100% composed of volunteers and interested parties, and has expanded into a large amount of related projects for saving online and digital history.
History is littered with hundreds of conflicts over the future of a community, group, location or business that were "resolved" when one of the parties stepped ahead and destroyed what was there. With the original point of contention destroyed, the debates would fall to the wayside. Archive Team believes that by duplicated condemned data, the conversation and debate can continue, as well as the richness and insight gained by keeping the materials. Our projects have ranged in size from a single volunteer downloading the data to a small-but-critical site, to over 100 volunteers stepping forward to acquire terabytes of user-created data to save for future generations.
The main site for Archive Team is at archiveteam.org and contains up to the date information on various projects, manifestos, plans and walkthroughs.
This collection contains the output of many Archive Team projects, both ongoing and completed. Thanks to the generous providing of disk space by the Internet Archive, multi-terabyte datasets can be made available, as well as in use by the Wayback Machine, providing a path back to lost websites and work.
Our collection has grown to the point of having sub-collections for the type of data we acquire. If you are seeking to browse the contents of these collections, the Wayback Machine is the best first stop. Otherwise, you are free to dig into the stacks to see what you may find.
The Archive Team Panic Downloads are full pulldowns of currently extant websites, meant to serve as emergency backups for needed sites that are in danger of closing, or which will be missed dearly if suddenly lost due to hard drive crashes or server failures.
Collection: Archive Team: The Github Hitrub
K rostyslav fixf3c96d0
string
●number
●boolean
●null
●undefined
const foo = 1; let bar = foo; bar = 9; console.log(foo, bar); // => 1, 91.2 Складні типи: Коли ви отримуєте доступ до складного типу, ви працюєте з посиланням на його значення. ●
object
●array
●function
const foo = [1, 2]; const bar = foo; bar[0] = 9; console.log(foo[0], bar[0]); // => 9, 9
const для всіх посилань; уникайте використання var. eslint: prefer-const, no-const-assign
Чому? Це убезпечить вас від переприсвоєння значення для вашого посилання, що може призвести до багів та складності розуміння коду.
// погано var a = 1; var b = 2; // добре const a = 1; const b = 2;2.2 Якщо ви пеприсвоюєте посилання - використовуйте
let замість var. eslint: no-var jscs: disallowVar
Чому? let має блочну область видимості, на відміну від var, область видимості котрого обмежена функцією.
// погано var count = 1; if (true) { count += 1; } // добре, використовуйте let. let count = 1; if (true) { count += 1; }2.3 Зауважте, що і
let і const мають блочну область видимості.
// const та let існують лише в межах блоку, в якому вони були визначені. { let a = 1; const b = 1; } console.log(a); // ReferenceError console.log(b); // ReferenceError
new Object. eslint: no-new-object
// погано const item = new Object(); // добре const item = {};3.2 Використовуйте вираховані імена властивостей, при створенні об'єктів з динамічними іменами властивостей. Чому? Вони дозволяють визначати всі властивості об'єкта в одному місці.
function getKey(k) { return `a key named ${k}`; } // погано const obj = { id: 5, name: 'San Francisco', }; obj[getKey('enabled')] = true; // добре const obj = { id: 5, name: 'San Francisco', [getKey('enabled')]: true, };3.3 Використовуйте скорочення для метода об'єкта. eslint:
object-shorthand jscs: requireEnhancedObjectLiterals
// погано const atom = { value: 1, addValue: function (value) { return atom.value + value; }, }; // добре const atom = { value: 1, addValue(value) { return atom.value + value; }, };3.4 Використовуйте скорочення значення властивості. eslint:
object-shorthand jscs: requireEnhancedObjectLiterals
Чому? Так менше писати і більш зрозуміло.
const lukeSkywalker = 'Luke Skywalker'; // погано const obj = { lukeSkywalker: lukeSkywalker, }; // добре const obj = { lukeSkywalker, };3.5 Групуйте ваші скорочені властивості на початку оголошення вашого об'єкту. Чому? Так легше сказати які властивості використовують скорочення.
const anakinSkywalker = 'Anakin Skywalker'; const lukeSkywalker = 'Luke Skywalker'; // погано const obj = { episodeOne: 1, twoJediWalkIntoACantina: 2, lukeSkywalker, episodeThree: 3, mayTheFourth: 4, anakinSkywalker, }; // добре const obj = { lukeSkywalker, anakinSkywalker, episodeOne: 1, twoJediWalkIntoACantina: 2, episodeThree: 3, mayTheFourth: 4, };●3.6 Беріть в лапки лише ті властивості, які є неприпустимими ідентифікаторами. eslint:
quote-props jscs: disallowQuotedKeysInObjects
Чому? В загальному, ми вважаємо, що так суб'єктивно легше читати. Це покращує підсвітку синтаксису, а також більш легко оптимізується багатьма JS двигунами.
// погано const bad = { 'foo': 3, 'bar': 4, 'data-blah': 5, }; // добре const good = { 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)); // найкраще const has = Object.prototype.hasOwnProperty; // закешовуємо результати пошуку у скоупі модуля. /* або */ import has from 'has'; … console.log(has.call(object, key));●3.8 Віддавайте перевагу
spread оператору над Object.assign для дрібного копіювання об'єктів. Використовуйте rest оператор для отримання нового об'єкта з певними відсутніми властивостями.
// дуже погано const original = { a: 1, b: 2 }; const copy = Object.assign(original, { c: 3 }); // це мутує `original` ಠ_ಠ delete copy.a; // це також // погано const original = { a: 1, b: 2 }; const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 } // добре const original = { a: 1, b: 2 }; const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 } const {a, ...noA } = copy; // noA => { b: 2, c: 3 }
no-array-constructor
// погано const items = new Array(); // добре const items = [];4.2 Використовуйте Array#push замість прямого запису елементів у масив.
const someStack = []; // погано someStack[someStack.length] = 'abracadabra'; // добре someStack.push('abracadabra');4.3 Використовуйте
...( spreads ) оператор масива для копіювання масивів.
// погано const len = items.length; const itemsCopy = []; let i; for (i = 0; i < len; i += 1) { itemsCopy[i] = items[i]; } // добре const itemsCopy = [...items];4.4 Для конвертації масивоподібних об'єктів в масив, використовуйте Array.from.
const foo = document.querySelectorAll('.foo'); const nodes = Array.from(foo);4.5 Використовуйте оператор
return у функціях зворотнього виклику методу масива. Це нормально не робити повернення, якщо тіло функції складається з одного визначення згідно з 8.2. eslint: array-callback-return
// добре [1, 2, 3].map((x) => { const y = x + 1; return x * y; }); // добре [1, 2, 3].map(x => x + 1); // погано const flat = {}; [[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => { const flatten = memo.concat(item); flat[index] = flatten; }); // добре const flat = {}; [[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => { const flatten = memo.concat(item); flat[index] = flatten; return flatten; }); // погано inbox.filter((msg) => { const { subject, author } = msg; if (subject === 'Mockingbird') { return author === 'Harper Lee'; } else { return false; } }); // добре inbox.filter((msg) => { const { subject, author } = msg; if (subject === 'Mockingbird') { return author === 'Harper Lee'; } return false; });
requireObjectDestructuring
Чому? Деструктурування вберігає вас від створення тимчасових посиланнь на ті властивості.
// погано function getFullName(user) { const firstName = user.firstName; const lastName = user.lastName; return `${firstName} ${lastName}`; } // добре function getFullName(user) { const { firstName, lastName } = user; return `${firstName} ${lastName}`; } // найкраще function getFullName({ firstName, lastName }) { return `${firstName} ${lastName}`; }5.2 Використовуйте деструктурування масивів. jscs:
requireArrayDestructuring
const arr = [1, 2, 3, 4]; // погано const first = arr[0]; const second = arr[1]; // добре const [first, second] = arr;5.3 Використовуйте деструктурування об'єкта, а не масива, для декількох повертаємих значеннь . jscs:
disallowArrayDestructuringReturn
Чому? Ви зможете з часом додати нові властивості або змінити послідовність речей не порушуючи розташування викликів.
// погано function processInput(input) { // то відбувається чудо return [left, right, top, bottom]; } // Виклик повинен подумати про послідовність повертаємих даних const [left, __, top] = processInput(input); // добре function processInput(input) { // то відбувається чудо return { left, right, top, bottom }; } // виклик обирає лише необхідні йому данні const { left, top } = processInput(input);
'' для рядків. eslint: quotes jscs: validateQuoteMarks
// погано const name = "Capt. Janeway"; // погано - літеральні шаблони мають містити інтерполяцію чи нові рядки const name = `Capt. Janeway`; // добре const name = 'Capt. Janeway';6.2 Рядки, які подовжують лінію більше ніж на 100 символів не повинні записуватись у кілька рядків за допомогою конкатенації Чому? З розбитими таким чином рядками болючіше працювати і вони роблять код важко читаємим.
// погано const errorMessage = 'This is a super long error that was thrown because \ of Batman. When you stop to think about how Batman had anything to do \ with this, you would get nowhere \ fast.'; // погано const errorMessage = 'This is a super long error that was thrown because ' + 'of Batman. When you stop to think about how Batman had anything to do ' + 'with this, you would get nowhere fast.'; // добре const errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.';6.3 Коли програмно будуєте рядки, використовуйте рядкові шаблони замість конкатенації. eslint:
prefer-template template-curly-spacing jscs: requireTemplateStrings
Чому? Рядкові шаблони дають читабельність, короткий синтаксис з переносом нових ліній та функціями інтерполяції рядка.
// погано function sayHi(name) { return 'How are you, ' + name + '?'; } // погано function sayHi(name) { return ['How are you, ', name, '?'].join(); } // погано function sayHi(name) { return `How are you, ${ name }?`; } // добре function sayHi(name) { return `How are you, ${name}?`; }●6.4 Ніколи не використовуйте
eval() на рядку, це відкриває дуже багато вразливостей.
6.5 Не зловживайте символами екранування у рядках. eslint: no-useless-escape
Чому? Зворотні слеші ('') шкодять читаємості, тому вони мають використовуватись лише там де дійсно необхідно.
// погано const foo = '\'this\' \i\s \"quoted\"'; // добре const foo = '\'this\' is "quoted"'; const foo = `my name is '${name}'`;
func-style jscs: disallowFunctionDeclarations
Чому? Функціональні оголошення хойстяться (вспливають уверх), це означає, що дуже легко послатися на функцію до того, як вона оголошена у файлі. Це шкодить читаємості та підтримуємості. Якщо вам здається, що визначення функції досить велике чи воно ускладнює розуміння іншої частини файлу, то, можливо, прийшов час, щоб виокремити це в окремий модуль! Не забувайте іменувати вирази - анонімні функції можуть ускладнити локалізацію проблеми у стеку викликів. (Discussion)
// погано const foo = function () { }; // погано function foo() { } // добре const foo = function bar() { };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) { function test() { console.log('Nope.'); } } // добре let test; if (currentUser) { test = () => { console.log('Yup.'); }; }7.5 Ніколи не називайте параметр як
arguments. Це матиме пріоритет над arguments об'єкта, який надається області видимості кожної функції.
// погано function nope(name, options, arguments) { // ...щось відбувається... } // добре function yup(name, options, args) { // ...щось відбувається... }7.6 Ніколи не використовуйте
arguments, краще натомість використовуйте rest синтаксис (...). eslint: prefer-rest-params
Чому? ... оператор явно зазначає, що ви хочете щось витягти. Крім того, rest аргументи являються реальним масивом, а не масивоподібністю, як arguments.
// погано function concatenateAll() { const args = Array.prototype.slice.call(arguments); return args.join(''); } // добре function concatenateAll(...args) { return args.join(''); }7.7 Використовуйте синтаксис "параметру за замовчуванням", а не мутуйте аргументи функції.
// насправді погано function handleThings(opts) { // Ні! Ми не повинні мутувати аргументи функції. // Двічі погано: якщо `opts` є неправдивим(`falsy` - прим. прекладача), то воно так і буде задано об'єкту. Це, звісно, може бути тим, що // вам саме потрібно, але це може призвести до тонких багів. opts = opts || {}; // ... } // все ще погано function handleThings(opts) { if (opts === void 0) { opts = {}; } // ... } // добре function handleThings(opts = {}) { // ... }7.8 Уникайте сторонніх ефектів при використанні параметрів за замовчуванням. Чому? Вони збентежують.
var b = 1; // погано function count(a= b++) { console.log(a); } count(); // 1 count(); // 2 count(3); // 3 count(); // 37.9 Завжди зазначайте параметри за замовчуванням останніми.
// погано function handleThings(opts = {}, name) { // ... } // добре function handleThings(name, opts = {}) { // ... }7.10 Ніколи не використовуйте конструктор функцій для створення нової функції. eslint:
no-new-func
Чому? Створення функції таким чином обчислює рядок аналогічно eval(), що, в свою чергу, відкриває вразливості.
// погано var add = new Function('a', 'b', 'return a + b'); // досі погано var subtract = Function('a', 'b', 'return a - b');7.11 Відступи у сигнатурі функції. eslint:
space-before-function-paren space-before-blocks
Чому? Постійність - це добре, і ви не повинні додавати або видаляти пробіл при додаванні або видаленні імені.
// погано const f = function(){}; const g = function (){}; const h = function() {}; // добре const x = function () {}; const y = function a() {};7.12 Ніколи не мутуйте параметри. eslint:
no-param-reassign
Чому? Маніпулювання об'єктами, які були передані як параметри, може призвести до небажаних побічних ефектів у змінних, у місці звідки відбувся початковий виклик.
// погано function f1(obj) { obj.key = 1; }; // добре function f2(obj) { const key = Object.prototype.hasOwnProperty.call(obj, 'key')?obj.key : 1; };7.13 Ніколи не перепризначайте параметри. eslint:
no-param-reassign
Чому? Перепризначення параметрів може призвести до неочікуваної поведінки, особливо, при доступі до об'єкту аргументів. Це також може викликати оптимізаційні проблеми, особливо у V8.
// погано function f1(a) { a = 1; } function f2(a) { if (!a) { a = 1; } } // добре function f3(a) { const b = a || 1; } function f4(a= 1) { }7.14 Віддавайте перевагу використанню
... (оператор spread) при виклику функцій зі змінним числом параметрів . eslint: prefer-spread
Чому? Так чистіше, вам не потрібно надавати контекст і ви не можете легко створити new за допомогою apply.
// погано const x = [1, 2, 3, 4, 5]; console.log.apply(console, x); // добре const x = [1, 2, 3, 4, 5]; console.log(...x); // погано new (Function.prototype.bind.apply(Date, [null, 2016, 08, 05])); // добре new Date(...[2016, 08, 05]);7.15 Функції з кількома сигнатурами, чи викликами, повинні бути з відступами, так само як і будь-який інший список у кілька рядків у цьому керівництві: з кожним елементом на своєму рядку, з комою у кінці кожного рядка.
// погано function foo(bar, baz, quux) { // тіло функції } // добре function foo( bar, baz, quux, ) { // тіло функції } // погано console.log(foo, bar, baz); // добре console.log( foo, bar, baz, );
prefer-arrow-callback, arrow-spacing jscs: requireArrowFunctions
Чому? Це створює версію функції, яка виконується у контексті this, що вам зазвичай і потрібно, і має коротший синтаксис.
Чому ні? Якщо у вас є досить складна функція, ви можете винести складну логіку з неї у її власну оголошену функцію.
// погано [1, 2, 3].map(function (x) { const y = x + 1; return x * y; }); // добре [1, 2, 3].map((x) => { const y = x + 1; return x * y; });8.2 Якщо тіло функцій складається з одного виразу - не застосовуйте фігурні дужки, а одразу використовуйте неявне повернення. Або, лишіть фігурні дужки і використайте оператор
return. eslint: arrow-parens, arrow-body-style jscs: disallowParenthesesAroundArrowParam, requireShorthandArrowFunctions
Чому? Синтаксичний цукор. Це гарно читається, особливо коли кілька функцій формують послідовний ланцюжок.
// погано [1, 2, 3].map(number => { const nextNumber = number + 1; `A string containing the ${nextNumber}.`; }); // добре [1, 2, 3].map(number => `A string containing the ${number}.`); // добре [1, 2, 3].map((number) => { const nextNumber = 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 => { const y = x + 1; return x * y; }); // добре [1, 2, 3].map((x) => { const y = x + 1; return x * y; });8.5 Уникайте синтаксису arrow-функції (
=>) з операторами порівняння (<=, >=), оскільки це може збити з пантелику. eslint: no-confusing-arrow
// погано const itemHeight = item => item.height > 256?item.largeSize : item.smallSize; // погано const itemHeight = (item) => item.height > 256?item.largeSize : item.smallSize; // добре const itemHeight = item => (item.height > 256?item.largeSize : item.smallSize); // добре const itemHeight = (item) => { const { height, largeSize, smallSize } = item; return height > 256?largeSize : smallSize; };
class. Уникайте маніпулювати prototype напряму.
Чому? class синтаксис коротший і його легше зрозуміти.
// погано function Queue(contents = []) { this.queue = [...contents]; } Queue.prototype.pop = function () { const value = this.queue[0]; this.queue.splice(0, 1); return value; }; // добре class Queue { constructor(contents = []) { this.queue = [...contents]; } pop() { const value = this.queue[0]; this.queue.splice(0, 1); return value; } }9.2 Використовуйте
extends для наслідування.
Чому? Це вбудований спосіб, щоб наслідувати функціональність прототипу, не порушуючи instanceof.
// погано const inherits = require('inherits'); function PeekableQueue(contents) { Queue.apply(this, contents); } inherits(PeekableQueue, Queue); PeekableQueue.prototype.peek = function () { return this._queue[0]; } // добре class PeekableQueue extends Queue { peek() { return this._queue[0]; } }9.3 Методи можуть повертати
this, щоб допомогти методу з побудовою ланцюжка.
// погано Jedi.prototype.jump = function () { this.jumping = true; return true; }; Jedi.prototype.setHeight = function (height) { this.height = height; }; const luke = new Jedi(); luke.jump(); // => true luke.setHeight(20); // => undefined // добре class Jedi { jump() { this.jumping = true; return this; } setHeight(height) { this.height = height; return this; } } const luke = new Jedi(); luke.jump() .setHeight(20);9.4 Це нормально писати власний toString() метод, просто переконайтесь, що він працює вдало і без побічних ефектів.
class Jedi { constructor(options = {}) { this.name = options.name || 'no name'; } getName() { return this.name; } toString() { return `Jedi - ${this.getName()}`; } }9.5 Класи мають конструктор за замовчуванням, якщо не вказано іншого. Порожній конструктор функції або конструктор, який просто посилається на батьківський клас не є необхідними. eslint:
no-useless-constructor
// погано class Jedi { constructor() {} getName() { return this.name; } } // погано class Rey extends Jedi { constructor(...args) { super(...args); } } // добре class Rey extends Jedi { constructor(...args) { super(...args); this.name = 'Rey'; } }9.6 Уникайте дублювання членів класу. eslint:
no-dupe-class-members
Чому? Продубльовані оголошення членів класу будуть нишком віддавати перевагу останньому, тому наявність дублікатів майже напевно - помилка.
// погано class Foo { bar() { return 1; } bar() { return 2; } } // добре class Foo { bar() { return 1; } } // добре class Foo { bar() { return 2; } }
import/export) модуля, а не нестандартній модульній системі. Ви завжди можете сконвертувати(transpile) до вашої улюбленої модульної системи.
Чому? Модулі - це майбутнє, тож давайте використовувати майбутнє вже зараз.
// погано const AirbnbStyleGuide = require('./AirbnbStyleGuide'); module.exports = AirbnbStyleGuide.es6; // нормально import AirbnbStyleGuide from './AirbnbStyleGuide'; export default AirbnbStyleGuide.es6; // найкраще import { es6 } from './AirbnbStyleGuide'; export default es6;10.2 Ніколи не вживайте непередбачувані імпорти. Чому? Це гарантує, що у вас по замовчуванню експортується лише один модуль.
// погано import * as AirbnbStyleGuide from './AirbnbStyleGuide'; // добре import AirbnbStyleGuide from './AirbnbStyleGuide';10.3 І не експортуйте напряму з імпорту. Чому? Не дивлячись на те, що одна строка це досить коротко, мати один чіткий шлях для імпорта і один чіткий шлях для експорта робить речі більш зрозумілими.
// погано // filename es6.js export { es6 as default } from './AirbnbStyleGuide'; // добре // filename es6.js import { es6 } from './AirbnbStyleGuide'; export default es6;10.4 Імпортуйте з одного місця лише раз. eslint:
no-duplicate-imports
Чому? Коли є кілька рядків, які імпортують з одного шляху - це ускладнює підтримку коду.
// погано import foo from 'foo'; // … some other imports … // import { named1, named2 } from 'foo'; // добре import foo, { named1, named2 } from 'foo'; // добре import foo, { named1, named2, } from 'foo';10.5 Не експортуйте мутабельні прив'язки. eslint:
import/no-mutable-exports
Чому? Взагалі, мутацій потрібно уникати, особливо при експорті мутабельних прив'язок. Хоча цей прийом(мутація) може бути потрібним в деяких особливих ситуаціях, але в загальному потрібно експортувати лише постійні посилання.
// погано let foo = 3; export { foo } // добре const foo = 3; export { foo }10.6 У модулі з єдиним експортом віддавайте превагу експорту за замовчуванням (
default), а не іменованому експорту.
eslint: import/prefer-default-export
// погано export function foo() {} // добре export default function foo() {}10.7 Зазначайте всі
import визначення над не імпортами.
eslint: import/first
Чому? Оскільки importи вспливають вгору, то тримати їх зверху убезпечує від неочікуваної поведінки.
// погано import foo from 'foo'; foo.init(); import bar from 'bar'; // добре import foo from 'foo'; import bar from '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.
// погано import fooSass from 'css!sass!foo.scss'; import barCss from 'style!css!bar.css'; // добре import fooSass from 'foo.scss'; import barCss from 'bar.css';
for-in чи for-of. eslint: no-iterator no-restricted-syntax
Чому? Це примушує дотримуватись нашого правила не мутувати дані. Легше працювати з чистими функціями які повертають значення, а не побічні ефекти.
Використовуйте map() / every() / filter() / find() / findIndex() / reduce() / some() / ... щоб перебирати масиви, і Object.keys() / Object.values() / Object.entries() для створення масивів, щоб мати змогу далі їх перебирати.
const numbers = [1, 2, 3, 4, 5]; // погано let sum = 0; for (let num of numbers) { sum += num; } sum === 15; // добре let sum = 0; numbers.forEach(num => sum += num); sum === 15; // найкраще (використовуйте функціональну силу) const sum = numbers.reduce((total, num) => total + num, 0); sum === 15; // погано const increasedByOne = []; for (let i = 0; i < numbers.length; i++) { increasedByOne.push(numbers[i] + 1); } // добре const increasedByOne = []; numbers.forEach(num => increasedByOne.push(num + 1)); // найкраще (притримуйтесь функціонального стилю) const increasedByOne = numbers.map(num => num + 1);11.2 Поки що не використовуйте генератори. Чому? Вони не досить добре перетворюються в ES5. 11.3 Якщо вам потрібно використати генератори, або якщо ви вирішили не скористатись нашою порадою our advice, переконайтесь, що сигнатура функції має правильні відступи. eslint:
generator-star-spacing
Чому? function і * є частиною одного концептуального ключового слова - * це не модифікатор function, function* - це унікальна конструкція, відмінна від function.
// погано function * foo() { } const bar = function * () { } const baz = function *() { } const quux = function*() { } function*foo() { } function *foo() { } // дуже погано function * foo() { } const wat = function * () { } // добре function* foo() { } const foo = function* () { }
dot-notation jscs: requireDotNotation
const luke = { jedi: true, age: 28, }; // погано const isJedi = luke['jedi']; // добре const isJedi = luke.jedi;12.2 Використовуйте квадратні дужки
[] при доступі до властивостей через змінні.
const luke = { jedi: true, age: 28, }; function getProp(prop) { return luke[prop]; } const isJedi = getProp('jedi');
const для оголошення змінних. Недотримання цієї вимоги призведе до глобальних змінних. Ми хочемо уникнути забруднення глобального простору імен. Капітан Планета застерігає нас від цього. eslint: no-undef prefer-const
// погано superPower = new SuperPower(); // добре const superPower = new SuperPower();13.2 Використовуйте по одному
const для кожної змінної. eslint: one-var jscs: disallowMultipleVarDecl
Чому? Так легше оголошувати змінні таким чином, що вам не потрібно буде хвилюватись, що ви випадково переплутаєте в кінці рядка ; з ,. Ви також можете пройти через кожне оголошення змінної за допомогою дебагера, замість того, щоб перестрибнути через всі оголошення змінних одразу.
// погано const items = getItems(), goSportsTeam = true, dragonball = 'z'; // погано // (порівняйте з верхнім і спробуйте знайти помилку) const items = getItems(), goSportsTeam = true; dragonball = 'z'; // добре const items = getItems(); const goSportsTeam = true; const dragonball = 'z';13.3 Спочатку групуйте всі ваші
const, а потім вже групуйте всі lets.
Чому? Це дуже зручно у випадку, коли в подальшому вам знадобиться оголосити зміну в залежності від вже оголошених змінних.
// погано let i, len, dragonball, items = getItems(), goSportsTeam = true; // погано let i; const items = getItems(); let dragonball; const goSportsTeam = true; let len; // добре const goSportsTeam = true; const items = getItems(); let dragonball; let i; let length;13.4 Призначайте змінні де вам потрібно, але розміщуйте їх лише у потрібних місцях. Чому?
let і const обмежуються блочною зоною видимості, а не функціональною.
// погано - непотрібний виклик функції function checkName(hasName) { const name = getName(); if (hasName === 'test') { return false; } if (name === 'test') { this.setName(''); return false; } return name; } // добре function checkName(hasName) { if (hasName === 'test') { return false; } const name = getName(); if (name === 'test') { this.setName(''); return false; } return name; }13.5 Не поєднуйте в ланцюжки присвоєння змінних. Чому? Поєднання змінних у ланцюжки створює неявні глобальні змінні.
// погано (function example() { // JavaScript інтерпретує це як // let a = ( b = ( c = 1 ) ); // Ключове слово let застосовується до змінної a; змінні b та c стають // глобальними змінними. let a = b = c = 1; }()); console.log(a); // undefined console.log(b); // 1 console.log(c); // 1 // добре (function example() { let a = 1; let b = a; let c = a; }()); console.log(a); // undefined console.log(b); // undefined console.log(c); // undefined // Те ж саме стосується і `const`13.6 Уникайте використання унарних збільшеннь та зменшеннь (++, --). eslint
no-plusplus
Чому? Згідно з документацією eslint, унарні збільшення або зменшення спричиняють автоматичну вставку крапки й коми, що, в свою чергу, може призвести до непомітних помилок при збільшенні або зменшенні значень у рамках програми. Також, більш виразно застосовувати для збільшеннь або зменшень такі вирази як num += 1 замість num++ або num ++. Заборона унарних збільшеннь або зменшеннь також захищає вас від випадкових попередніх збільшеннь/зменшень, які також можуть призвести до непередбачуваної поведінки у ваших програмах.
// погано let array = [1, 2, 3]; let num = 1; num++; --num; let sum = 0; let truthyCount = 0; for(let i = 0; i < array.length; i++){ let value = array[i]; sum += value; if (value) { truthyCount++; } } // добре let array = [1, 2, 3]; let num = 1; num += 1; num -= 1; const sum = array.reduce((a, b) => a + b, 0); const truthyCount = array.filter(Boolean).length;
var, піднімаються вгору обсласті видимості функції, в той час як привласнені їм значення - ні. Змінні, оголошені за допомогою const та let отримали нову концепцію - Тимчасові Мертві Зони (ТМЗ). Важливо знати, чому використовувати typeof тепер небезпечно.
// ми знаємо, що це не спрацює (припустимо, що // не існує глобальної змінної notDefined) function example() { console.log(notDefined); // => видасть ReferenceError } // створення змінної після того, // як на неї зіслались спрацює завдяки підйому змінної // Зауважте: присвоєне змінній значення `true` не підніметься вгору. function example() { console.log(declaredButNotAssigned); // => undefined var declaredButNotAssigned = true; } // інтерпретатор піднімає проголошення змінної // вверх області видимості, // що означає, що наш приклад може бути записаним як: function example() { let declaredButNotAssigned; console.log(declaredButNotAssigned); // => undefined declaredButNotAssigned = true; } // використовуючи const та let function example() { console.log(declaredButNotAssigned); // => видасть ReferenceError console.log(typeof declaredButNotAssigned); // => видасть ReferenceError const declaredButNotAssigned = true; }14.2 Анонімні функціональні вирази піднімають ім'я змінної, але не функціональне присвоєння.
function example() { console.log(anonymous); // => undefined anonymous(); // => TypeError anonymous is not a function var anonymous = function () { console.log('anonymous function expression'); }; }14.3 Іменовані функціональні вирази піднімають ім'я змінної, але не ім'я функції чи тіло функції.
function example() { console.log(named); // => undefined named(); // => TypeError named is not a function superPower(); // => ReferenceError superPower is not defined var named = function superPower() { console.log('Flying'); }; } // це також стосується і випадку, // коли ім'я функції співпадає з іменем змінної. function example() { console.log(named); // => undefined named(); // => TypeError named is not a function var named = function named() { console.log('named'); } }14.4 Функціональне оголошення піднімає ім'я і тіло функції.
function example() { superPower(); // => Flying function superPower() { console.log('Flying'); } }За більш детальною інформацією звертайтесь до JavaScript Scoping & Hoisting автор Ben Cherry.
=== та !== а не == і не !=. 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.4 Більш детальну інформацію дивіться у статті Truth Equality and JavaScript автора Angus Croll. ●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.
// погано const foo = maybe1 > maybe2?"bar" : value1 > value2?"baz" : null; // краще const maybeNull = value1 > value2?'baz' : null; const foo = maybe1 > maybe2?'bar' : maybeNull; // найкраще const maybeNull = value1 > value2?'baz' : null; const foo = maybe1 > maybe2?'bar' : maybeNull;15.7 Уникайте непотрібних тернарних записів. eslint rules:
no-unneeded-ternary.
// погано const foo = a?a : b; const bar = c?true : false; const baz = c?false : true; // добре const foo = a || b; const bar =!!c; const baz =!c;
// погано if (test) return false; // добре if (test) return false; // добре if (test) { return false; } // погано function foo() { return false; } // добре function bar() { return false; }16.2 Якщо ви використовуєте блоки у кілька рядків з
ifта else, то ставте else на тому самому рядку, що і закриваюча дужка ifблоку. eslint: brace-style jscs: disallowNewlineBeforeBlockStatements
// погано if (test) { thing1(); thing2(); } else { thing3(); } // добре if (test) { thing1(); thing2(); } else { thing3(); }
/** ... */ для коментарів у кілька рядків.
// погано // make() returns a new element // based on the passed in tag name // // @param {String} tag // @return {Element} element function make(tag) { // ...stuff... return element; } // добре /** * make() returns a new element * based on the passed-in tag name */ function make(tag) { // ...stuff... return element; }17.2 Використовуйте
// для коментарів в один рядок. Ставте однорядковий коментар на новий рядок одразу над суб'єктом, до якого відноситься цей коментар. Ставте порожній рядок перед коментарем, якщо тільки це не перший рядок блоку.
// погано const active = true; // is current tab // добре // is current tab const active = true; // погано function getType() { console.log('fetching type...'); // set the default type to 'no type' const type = this._type || 'no type'; return type; } // добре function getType() { console.log('fetching type...'); // set the default type to 'no type' const type = this._type || 'no type'; return type; } // також добре function getType() { // set the default type to 'no type' const type = this._type || 'no type'; return type; }17.3 Починайте всі коментарі з пробілу для більше легкого читання. eslint:
spaced-comment
// погано //is current tab const active = true; // добре // is current tab const active = true; // погано /** *make() returns a new element *based on the passed-in tag name */ function make(tag) { // ...stuff... return element; } // добре /** * make() returns a new element * based on the passed-in tag name */ function make(tag) { // ...stuff... return element; }●17.4 Починати ваш коментар зі слів
FIXME чи TODO добре, оскільки це допомагає іншим розробникам швидко розуміти, чи ви відзначаєте проблемне місце в коді, яке треба переглянути, чи ви пропонуєте вирішення проблеми, яке має бути запроваджене. Вони відрізняються від звичайних коментарів, оскільки вони вимагають дії. Дія може бути FIXME: -- потрібно в цьому розібратись і виправитиorTODO: -- потрібно запровадити.
17.5 Використовуйте // FIXME: для описання проблеми.
class Calculator extends Abacus { constructor() { super(); // FIXME: shouldn't use a global here total = 0; } }17.6 Використовуйте
// TODO: для описання способів вирішення проблеми.
class Calculator extends Abacus { constructor() { super(); // TODO: total should be configurable by an options param this.total = 0; } }
indent jscs: validateIndentation
// погано function foo() { ∙∙∙∙const name; } // погано function bar() { ∙const name; } // добре function baz() { ∙∙const name; }18.2 Ставте 1 пробіл перед ведучою фігурною дужкою. eslint:
space-before-blocks jscs: requireSpaceBeforeBlockStatements
// погано function test(){ console.log('test'); } // добре function test() { 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(); } // погано function fight () { console.log ('Swooosh!'); } // добре function fight() { console.log('Swooosh!'); }18.4 Розмежовуйте оператори пробілами. eslint:
space-infix-ops jscs: requireSpaceBeforeBinaryOperators, requireSpaceAfterBinaryOperators
// погано const x=y+5; // добре const x = y + 5;18.5 Лишайте символ нового рядку у кінці файлу. eslint:
eol-last
// погано import { es6 } from './AirbnbStyleGuide'; // ... export default es6;
// погано import { es6 } from './AirbnbStyleGuide'; // ... export default es6;↵ ↵
// добре import { es6 } from './AirbnbStyleGuide'; // ... export default es6;↵18.6 Використовуйте відступи, коли робите ланцюжки методів (більш ніж два методи у ланцюгу). Використовуйте ведучу крапку, яка підкреслює, що на новій лінії відбувається виклик методу, а не нове ствердження. eslint:
newline-per-chained-call no-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(); // погано const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true) .attr('width', (radius + margin) * 2).append('svg:g') .attr('transform', `translate(${radius + margin},${radius + margin})`) .call(tron.led); // добре const leds = stage.selectAll('.led') .data(data) .enter().append('svg:svg') .classed('led', true) .attr('width', (radius + margin) * 2) .append('svg:g') .attr('transform', `translate(${radius + margin},${radius + margin})`) .call(tron.led); // добре const leds = stage.selectAll('.led').data(data);18.7 Лишайте порожній рядок після блоків і перед наступним ствердженням. jscs:
requirePaddingNewLinesAfterBlocks
// погано if (foo) { return bar; } return baz; // добре if (foo) { return bar; } return baz; // погано const obj = { foo() { }, bar() { }, }; return obj; // добре const obj = { foo() { }, bar() { }, }; return obj; // погано const arr = [ function foo() { }, function bar() { }, ]; return arr; // добре const arr = [ function foo() { }, function bar() { }, ]; return arr;18.8 Не насичуйте ваші блоки порожніми лініями. eslint:
padded-blocks jscs: disallowPaddingNewlinesInBlocks
// погано function bar() { console.log(foo); } // також погано if (baz) { console.log(qux); } else { console.log(foo); } // добре function bar() { console.log(foo); } // добре if (baz) { console.log(qux); } else { console.log(foo); }18.9 Не додавайте пробілів в середині дужок. eslint:
space-in-parens jscs: disallowSpacesInsideParentheses
// погано function bar( foo ) { return foo; } // добре function bar(foo) { return foo; } // погано if ( foo ) { console.log(foo); } // добре if (foo) { console.log(foo); }18.10 Не ставте зайвих пробілів в середині квадратних дужок. eslint:
array-bracket-spacing jscs: disallowSpacesInsideArrayBrackets
// погано const foo = [ 1, 2, 3 ]; console.log(foo[ 0 ]); // добре const foo = [1, 2, 3]; console.log(foo[0]);18.11 Додавайте пробіли в середині фігурних дужок. eslint:
object-curly-spacing jscs: requireSpacesInsideObjectBrackets
// погано const foo = {clark: 'kent'}; // добре const foo = { clark: 'kent' };18.12 Уникайте ліній коду, що довші за 100 символів (включаючи пробіли). Примітка: зазначені тут довгі рядки не підпадають під це правило і не повинні розбиватись. eslint:
max-len jscs: maximumLineLength
Чому? Це забезпечує читаємість та підтримку.
// погано const foo = 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.')); // добре const foo = 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.'));
comma-style jscs: requireCommaBeforeLineBreak
// погано const story = [ once , upon , aTime ]; // добре const story = [ once, upon, aTime, ]; // погано const hero = { firstName: 'Ada' , lastName: 'Lovelace' , birthYear: 1815 , superPower: 'computers' }; // добре const hero = { 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'],
};
// погано const hero = { firstName: 'Dana', lastName: 'Scully' }; const heroes = [ 'Batman', 'Superman' ]; // добре const hero = { firstName: 'Dana', lastName: 'Scully', }; const heroes = [ 'Batman', 'Superman', ]; // погано function createHero( firstName, lastName, inventorOf ) { // does nothing } // добре function createHero( firstName, lastName, inventorOf, ) { // does nothing } // добре (зауважте, що кома не повинна з'являтись після "rest" елементу) function createHero( firstName, lastName, inventorOf, ...heroArgs ) { // does nothing } // погано createHero( firstName, lastName, inventorOf ); // добре createHero( firstName, lastName, inventorOf, ); // добре (зауважте, що кома не повинна з'являтись після "rest" елементу) createHero( firstName, lastName, inventorOf, ...heroArgs )
semi jscs: requireSemicolons
// погано (function () { const name = 'Skywalker' return name })() // добре (function () { const name = 'Skywalker'; return name; }()); // добре, але застаріло (захист, щоб функція не перетворювалась на аргумент, коли об'єднуються два файли за допомогою IIFEs(негайно виконуваний функціональний вираз (НВФВ))) ;(() => { const name = 'Skywalker'; return name; }());Прочитати більше.
// => this.reviewScore = 9; // погано const totalScore = this.reviewScore + ''; // викликає this.reviewScore.valueOf() // погано const totalScore = this.reviewScore.toString(); // не гарантовано, що повернеться рядок // добре const totalScore = String(this.reviewScore);21.3 Цифри: Використовуйте
Number для приведення типу та parseInt завжди з десятичною для синтаксичного аналізу рядків. eslint: radix
const inputValue = '4'; // погано const val = new Number(inputValue); // погано const val = +inputValue; // погано const val = inputValue >> 0; // погано const val = parseInt(inputValue); // добре const val = Number(inputValue); // добре const val = parseInt(inputValue, 10);21.4 Якщо, з якоїсь причини, ви робите щось дике і
parseInt являється слабкою ланкою і вам потрібно використати бітову операцію заради ефективності, залиште коментар, який пояснює навіщо і що ви робите.
// добре /** * parseInt сповільнював код. * Застосування бітової операції щодо рядка для примусового приведення до * Number робить код набагато швидшим. */ const val = inputValue >> 0;21.5 Зауважте: Будьте обачні при використанні бітових операцій. Цифри представленні як 64-бітні значення, але бітові операції завжди повертають 32-bit ціле число (джерело). Бітова операція може призвести до непердбачуваної поведінки для цілик значеннь, більших ніж 32-біта. Обговорення. Найбільшим виявленим 32-бітним цілим числом є 2,147,483,647:
2147483647 >> 0 //=> 2147483647 2147483648 >> 0 //=> -2147483648 2147483649 >> 0 //=> -214748364721.6 Булеві значення:
const age = 0; // погано const hasAge = new Boolean(age); // добре const hasAge = Boolean(age); // best const hasAge =!!age;
id-length
// погано function q() { // ...stuff... } // добре function query() { // ..stuff.. }22.2 Використовуйте
camelCase коли називаєте об'єкти, функції і екземпляри. eslint: camelcase jscs: requireCamelCaseOrUpperCaseIdentifiers
// погано const OBJEcttsssss = {}; const this_is_my_object = {}; function c() {} // добре const thisIsMyObject = {}; function thisIsMyFunction() {}22.3 Використовуйте PascalCase лише коли називаєте конструктори чи класи. eslint:
new-cap jscs: requireCapitalizedConstructors
// погано function user(options) { this.name = options.name; } const bad = new user({ name: 'nope', }); // добре class User { constructor(options) { this.name = options.name; } } const good = new User({ 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
// погано function foo() { const self = this; return function () { console.log(self); }; } // погано function foo() { const that = this; return function () { console.log(that); }; } // добре function foo() { return () => { console.log(this); }; }22.6 Базове ім'я файлу має співпадати з експортом за замовчуванням.
// файл 1 містить class CheckBox { // ... } export default CheckBox; // файл 2 містить export default function fortyTwo() { return 42; } // файл 3 містить export default function insideDirectory() {} // у якомусь іншому файлі // погано import CheckBox from './checkBox'; // PascalCase import/export, camelCase filename import FortyTwo from './FortyTwo'; // PascalCase import/filename, camelCase export import InsideDirectory from './InsideDirectory'; // PascalCase import/filename, camelCase export // погано import CheckBox from './check_box'; // PascalCase import/export, snake_case filename import forty_two from './forty_two'; // snake_case import/filename, camelCase export import inside_directory from './inside_directory'; // snake_case import, camelCase export import index from './inside_directory/index'; // requiring the index file explicitly import insideDirectory from './insideDirectory/index'; // requiring the index file explicitly // добре import CheckBox from './CheckBox'; // PascalCase export/import/filename import fortyTwo from './fortyTwo'; // camelCase export/import/filename import insideDirectory from './insideDirectory'; // camelCase export/import/directory name/implicit "index" // ^ supports both insideDirectory.js and insideDirectory/index.js22.7 Використовуйте camelCase коли ви експортуєте за замовчуванням function. Ім'я файлу повинно співпадати з іменем функції.
function makeStyleGuide() { } export default makeStyleGuide;22.8 Використовуйте PascalCase коли ви експортуєте конструктор / клас / функціональну бібліотеку / чистий об'єкт.
const AirbnbStyleGuide = { es6: { } }; export default AirbnbStyleGuide;22.9 Скорочення або абревіатури повинні завжди всі писатись або великими або маленькими літерами. Чому? Імена для зручності читання, а не для вдоволення комп'ютерного алгоритму.
// погано import SmsContainer from './containers/SmsContainer'; // погано const HttpRequests = [ // ... ]; // добре import SMSContainer from './containers/SMSContainer'; // добре const HTTPRequests = [ // ... ]; // найкраще import TextMessageContainer from './containers/TextMessageContainer'; // найкраще const Requests = [ // ... ];
// погано class Dragon { get age() { // ... } set age(value) { // ... } } // добре class Dragon { getAge() { // ... } setAge(value) { // ... } }23.3 Якщо властивість/метод являються
boolean, використовуйте isVal() або hasVal().
// погано if (!dragon.age()) { return false; } // добре if (!dragon.hasAge()) { return false; }23.4 Це нормально створювати get() та set() функції, але будьте послідовні.
class Jedi { constructor(options = {}) { const lightsaber = options.lightsaber || 'blue'; this.set('lightsaber', lightsaber); } set(key, val) { this[key] = val; } get(key) { return this[key]; } }
// погано $(this).trigger('listingUpdated', listing.id); ... $(this).on('listingUpdated', (e, listingId) => { // зробити щось з listingId });віддати перевагу такому:
// добре $(this).trigger('listingUpdated', { listingId: listing.id }); ... $(this).on('listingUpdated', (e, data) => { // зробити щось з data.listingId });
$. jscs: requireDollarBeforejQueryAssignment
// погано const sidebar = $('.sidebar'); // добре const $sidebar = $('.sidebar'); // добре const $sidebarBtn = $('.sidebar-btn');25.2 Кешуйте результати пошуку jQuery.
// погано function setSidebar() { $('.sidebar').hide(); // ...щось відбувається... $('.sidebar').css({ 'background-color': 'pink' }); } // добре function setSidebar() { 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();
function foo() { return true; }●28.2 Ні, але серйозно: ●Який би тестувальний фреймфорк ви б не використовували - ви повинні писати тести! ●Намагайтесь писати багато дрібних функцій та зводити до мінімуму місця, де відбуваються мутації. ●Будьте обережними з stubs та mocks, оскільки вони можуть зробити ваші тести більш крихкими. ●Ми в першу чергу використовуємо
mocha у Airbnb. tape також час від часу використовується для малньких, окремих модулів.
●100% покриття тестами - це гарна мета до якої варто прагнути, навіть якщо це не завжди практично.
●Кожного разу, коли ви виправляєте помилку, пишіть тест регресії. Помилка виправлена без написання регресивного тесту майже точно виникне в майбутньому знову.
map(), reduce(), and filter() optimized for traversing arrays?
●Loading...
Brazilian Portuguese: armoucar/javascript-style-guide
Bulgarian: borislavvv/javascript
Catalan: fpmweb/javascript-style-guide
Chinese (Simplified): sivan/javascript-style-guide
Chinese (Traditional): jigsawye/javascript
French: nmussy/javascript-style-guide
German: timofurrer/javascript-style-guide
Italian: sinkswim/javascript-style-guide
Japanese: mitsuruog/javascript-style-guide
Korean: tipjs/javascript-style-guide
Polish: mjurczyk/javascript
Russian: uprock/javascript
Spanish: paolocarrasco/javascript-style-guide
Thai: lvarayut/javascript-style-guide
Vietnam: hngiang/javascript-style-guide