Photo by Pankaj Patel on Unsplash
Airbnb JavaScript Styleguide()
Ein größtenteils vernünftiger Ansatz für JavaScript.
Andere Styleguides
Übersetzt von Airbnb JavaScript Style Guide.
Typen (Types)
- 1.1 Primitive (Primitives): Auf primitive Typen wird direkt zugegriffen.
stringnumberbooleannullundefined
const foo = 1;
let bar = foo;
bar = 9;
console.log(foo, bar); // => 1, 9
- 1.2 Komplexe (Complex): Auf komplexe Typen wird per Referenz (by reference) zugegriffen.
objectarrayfunction
const foo = [1, 2];
const bar = foo;
bar[0] = 9;
console.log(foo[0], bar[0]); // => 9, 9
Referenzen (References)
- 2.1 Verwende
constfür alle deine Referenzen; vermeide die Verwendung vonvar. eslint:prefer-const,no-const-assign
Warum? Dies stellt sicher, dass du deine Referenzen nicht neu zuweisen kannst, was zu Fehlern und schwer verständlichem Code führen kann.
// bad
var a = 1;
var b = 2;
// good
const a = 1;
const b = 2;
- 2.2 Wenn du Referenzen neu zuweisen musst, verwende
letanstelle vonvar. eslint:no-varjscs:disallowVar
Warum?
letist block-scoped, währendvarfunction-scoped ist.
// bad
var count = 1;
if (true) {
count += 1;
}
// good, use the let.
let count = 1;
if (true) {
count += 1;
}
- 2.3 Beachte, dass sowohl
letals auchconstblock-scoped sind.
// const und let existieren nur innerhalb der Blöcke, in denen sie definiert sind.
{
let a = 1;
const b = 1;
}
console.log(a); // ReferenceError
console.log(b); // ReferenceError
Objekte (Objects)
- 3.1 Verwende die wörtliche Syntax (literal syntax) für die Objekterstellung. eslint rules:
no-new-object.
// bad
const item = new Object();
// good
const item = {};
- 3.2 Verwende keine reservierten Wörter als Schlüssel. Es wird im IE8 nicht funktionieren. Mehr Info. Es ist jedoch in Ordnung, sie in ES6-Modulen und serverseitigem Code zu verwenden. jscs:
disallowIdentifierNames
// bad
const superman = {
default: { clark: 'kent' },
private: true,
};
// good
const superman = {
defaults: { clark: 'kent' },
hidden: true,
};
- 3.3 Verwende lesbare Synonyme anstelle von reservierten Wörtern. jscs:
disallowIdentifierNames
// bad
const superman = {
class: 'alien',
};
// bad
const superman = {
klass: 'alien',
};
// good
const superman = {
type: 'alien',
};
- 3.4 Verwende berechnete Eigenschaftsnamen (computed property names), wenn du Objekte mit dynamischen Eigenschaftsnamen erstellst.
Warum? Sie ermöglichen es dir, alle Eigenschaften des Objekts an einer Stelle zu definieren.
function getKey(k) {
return `a key named ${k}`;
}
// bad
const obj = {
id: 5,
name: 'San Francisco',
};
obj[getKey('enabled')] = true;
// good
const obj = {
id: 5,
name: 'San Francisco',
[getKey('enabled')]: true,
};
- 3.5 Verwende die Kurzschreibweise für Objektmethoden (object method shorthand). eslint:
object-shorthandjscs:requireEnhancedObjectLiterals
// bad
const atom = {
value: 1,
addValue: function (value) {
return atom.value + value;
},
};
// good
const atom = {
value: 1,
addValue(value) {
return atom.value + value;
},
};
- 3.6 Verwende die Kurzschreibweise für Eigenschaftswerte (property value shorthand). eslint:
object-shorthandjscs:requireEnhancedObjectLiterals
Warum? Es ist kürzer und beschreibender.
const lukeSkywalker = 'Luke Skywalker';
// bad
const obj = {
lukeSkywalker: lukeSkywalker,
};
// good
const obj = {
lukeSkywalker,
};
- 3.7 Gruppiere deine Kurzschreibweisen am Anfang deiner Objektdeklaration.
Warum? Es ist einfacher zu erkennen, welche Eigenschaften die Kurzschreibweise verwenden.
const anakinSkywalker = 'Anakin Skywalker';
const lukeSkywalker = 'Luke Skywalker';
// bad
const obj = {
episodeOne: 1,
twoJediWalkIntoACantina: 2,
lukeSkywalker,
episodeThree: 3,
mayTheFourth: 4,
anakinSkywalker,
};
// good
const obj = {
lukeSkywalker,
anakinSkywalker,
episodeOne: 1,
twoJediWalkIntoACantina: 2,
episodeThree: 3,
mayTheFourth: 4,
};
- 3.8 Setze nur Eigenschaften in Anführungszeichen, die ungültige Bezeichner sind. eslint:
quote-propsjscs:disallowQuotedKeysInObjects
Warum? Im Allgemeinen halten wir es subjektiv für einfacher zu lesen. Es verbessert die Syntaxhervorhebung und ist auch von vielen JS-Engines einfacher zu optimieren.
// bad
const bad = {
'foo': 3,
'bar': 4,
'data-blah': 5,
};
// good
const good = {
foo: 3,
bar: 4,
'data-blah': 5,
};
Arrays (Arrays)
- 4.1 Verwende die wörtliche Syntax (literal syntax) für die Array-Erstellung. eslint:
no-array-constructor
// bad
const items = new Array();
// good
const items = [];
- 4.2 Verwende Array#push anstelle der direkten Zuweisung, um Elemente zu einem Array hinzuzufügen.
const someStack = [];
// bad
someStack[someStack.length] = 'abracadabra';
// good
someStack.push('abracadabra');
- 4.3 Verwende Array-Spreads
..., um Arrays zu kopieren.
// bad
const len = items.length;
const itemsCopy = [];
let i;
for (i = 0; i < len; i++) {
itemsCopy[i] = items[i];
}
// good
const itemsCopy = [...items];
- 4.4 Um ein array-ähnliches Objekt in ein Array zu konvertieren, verwende Array#from.
const foo = document.querySelectorAll('.foo');
const nodes = Array.from(foo);
- 4.5 Verwende Rückgabeanweisungen in Array-Methoden-Callbacks. Es ist in Ordnung, die Rückgabe wegzulassen, wenn der Funktionskörper aus einer einzigen Anweisung besteht, die 8.2 folgt. eslint:
array-callback-return
// good
[1, 2, 3].map((x) => {
const y = x + 1;
return x * y;
});
// good
[1, 2, 3].map(x => x + 1);
// bad
const flat = {};
[[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => {
const flatten = memo.concat(item);
flat[index] = memo.concat(item);
});
// good
const flat = {};
[[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => {
const flatten = memo.concat(item);
flat[index] = flatten;
return flatten;
});
// bad
inbox.filter((msg) => {
const { subject, author } = msg;
if (subject === 'Mockingbird') {
return author === 'Harper Lee';
} else {
return false;
}
});
// good
inbox.filter((msg) => {
const { subject, author } = msg;
if (subject === 'Mockingbird') {
return author === 'Harper Lee';
}
return false;
});
Destrukturierung (Destructuring)
- 5.1 Verwende die Objekt-Destrukturierung, wenn du auf mehrere Eigenschaften eines Objekts zugreifst und diese verwendest. jscs:
requireObjectDestructuring
Warum? Die Destrukturierung erspart dir das Erstellen temporärer Referenzen für diese Eigenschaften.
// bad
function getFullName(user) {
const firstName = user.firstName;
const lastName = user.lastName;
return `${firstName} ${lastName}`;
}
// good
function getFullName(user) {
const { firstName, lastName } = user;
return `${firstName} ${lastName}`;
}
// best
function getFullName({ firstName, lastName }) {
return `${firstName} ${lastName}`;
}
- 5.2 Verwende die Array-Destrukturierung. jscs:
requireArrayDestructuring
const arr = [1, 2, 3, 4];
// bad
const first = arr[0];
const second = arr[1];
// good
const [first, second] = arr;
- 5.3 Verwende die Objekt-Destrukturierung für mehrere Rückgabewerte, nicht die Array-Destrukturierung.
Warum? Du kannst neue Eigenschaften hinzufügen oder die Reihenfolge der Dinge ändern, ohne die Aufrufstellen (call sites) zu beschädigen.
// bad
function processInput(input) {
// then a miracle occurs
return [left, right, top, bottom];
}
// the caller needs to think about the order of return data
const [left, __, top] = processInput(input);
// good
function processInput(input) {
// then a miracle occurs
return { left, right, top, bottom };
}
// the caller selects only the data they need
const { left, right } = processInput(input);
Strings (Strings)
- 6.1 Verwende einfache Anführungszeichen
''für Strings. eslint:quotesjscs:validateQuoteMarks
// bad
const name = "Capt. Janeway";
// good
const name = 'Capt. Janeway';
- 6.2 Strings, die dazu führen, dass die Zeile 100 Zeichen überschreitet, sollten nicht über mehrere Zeilen mit String-Verkettung geschrieben werden.
- 6.3 Hinweis: Wenn sie übermäßig verwendet wird, kann eine lange String-Verkettung die Leistung beeinträchtigen. jsPerf & Diskussion.
// bad
const errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.';
// bad
const errorMessage = 'This is a super long error that was thrown because \
of Batman. When you stop to think about how Batman had anything to do \
with this, you would get nowhere \
fast.';
// good
const errorMessage = 'This is a super long error that was thrown because ' +
'of Batman. When you stop to think about how Batman had anything to do ' +
'with this, you would get nowhere fast.';
- 6.4 Wenn du Strings programmgesteuert erstellst, verwende Template-Strings anstelle von Verkettung. eslint:
prefer-templatetemplate-curly-spacingjscs:requireTemplateStrings
Warum? Template-Strings geben dir eine lesbare, prägnante Syntax mit korrekten Zeilenumbrüchen und String-Interpolationsfunktionen.
// bad
function sayHi(name) {
return 'How are you, ' + name + '?';
}
// bad
function sayHi(name) {
return ['How are you, ', name, '?'].join();
}
// bad
function sayHi(name) {
return `How are you, ${ name }?`;
}
// good
function sayHi(name) {
return `How are you, ${name}?`;
}
- 6.5 Verwende niemals
eval()in einem String, das öffnet zu viele Schwachstellen.
Funktionen (Functions)
- 7.1 Verwende Funktionsdeklarationen (function declarations) anstelle von Funktionsausdrücken (function expressions). jscs:
requireFunctionDeclarations
Warum? Funktionsdeklarationen sind benannt, daher sind sie in Stack-Traces leichter zu identifizieren. Außerdem werden Funktionsdeklarationen gehoistet (nach oben verschoben), Funktionsausdrücke hingegen nicht. Diese Regel macht es für Arrow Functions einfach, Funktionsausdrücke vollständig zu ersetzen.
// bad
const foo = function () {
};
// good
function foo() {
}
- 7.2 IIFE: eslint:
wrap-iifejscs:requireParenthesesAroundIIFE
Warum? Eine IIFE ist eine einzelne Einheit – das Einwickeln der Funktion und ihres Aufrufs in Klammern macht dies deutlich. Beachte, dass du in einer Welt mit Modulen fast keine IIFE benötigst.
// immediately-invoked function expression (IIFE)
(function () {
console.log('Welcome to the Internet. Please follow me.');
}());
-
7.3 Deklariere niemals eine Funktion in einem Nicht-Funktionsblock (if, while, etc). Weise die Funktion stattdessen einer Variablen zu. Browser erlauben dies zwar, interpretieren es aber alle unterschiedlich. eslint:
no-loop-func -
7.4 Hinweis: ECMA-262 definiert einen
Blockals eine Liste von Anweisungen. Eine Funktionsdeklaration ist keine Anweisung. Lies die Anmerkung von ECMA-262 zu diesem Problem.
// bad
if (currentUser) {
function test() {
console.log('Nope.');
}
}
// good
let test;
if (currentUser) {
test = () => {
console.log('Yup.');
};
}
- 7.5 Benenne einen Parameter niemals
arguments. Dies hat Vorrang vor demarguments-Objekt, das jedem Funktionsumfang gegeben wird.
// bad
function nope(name, options, arguments) {
// ...stuff...
}
// good
function yup(name, options, args) {
// ...stuff...
}
- 7.6 Verwende niemals
arguments, entscheide dich stattdessen für die Rest-Syntax....prefer-rest-params
Warum?
...macht explizit, welche Argumente du abrufen möchtest. Außerdem sind Rest-Argumente ein echtes Array und nicht nur Array-ähnlich wiearguments.
// bad
function concatenateAll() {
const args = Array.prototype.slice.call(arguments);
return args.join('');
}
// good
function concatenateAll(...args) {
return args.join('');
}
- 7.7 Verwende die Standardparametersyntax (default parameter syntax), anstatt Funktionsargumente zu verändern.
// really bad
function handleThings(opts) {
// No! We shouldn't mutate function arguments.
// Double bad: if opts is false it will be set to an object which may
// be what you want but it can cause subtle bugs.
opts = opts || {};
// ...
}
// still bad
function handleThings(opts) {
if (opts === void 0) {
opts = {};
}
// ...
}
// good
function handleThings(opts = {}) {
// ...
}
- 7.8 Vermeide Nebenwirkungen mit Standardparametern.
Warum? Sie sind verwirrend zu verstehen.
var b = 1;
// bad
function count(a = b++) {
console.log(a);
}
count(); // 1
count(); // 2
count(3); // 3
count(); // 3
- 7.9 Setze Standardparameter immer an die letzte Stelle.
// bad
function handleThings(opts = {}, name) {
// ...
}
// good
function handleThings(name, opts = {}) {
// ...
}
- 7.10 Verwende niemals den Function-Konstruktor, um eine neue Funktion zu erstellen.
Warum? Das Erstellen einer Funktion auf diese Weise wertet einen String ähnlich wie eval() aus, was Schwachstellen öffnet.
// bad
var add = new Function('a', 'b', 'return a + b');
// still bad
var subtract = Function('a', 'b', 'return a - b');
- 7.11 Abstand in einer Funktionssignatur.
Warum? Konsistenz ist gut, und du solltest keinen Platz hinzufügen oder entfernen müssen, wenn du einen Namen hinzufügst oder entfernst.
// bad
const f = function(){};
const g = function (){};
const h = function() {};
// good
const x = function () {};
const y = function a() {};
- 7.12 Verändere niemals Parameter. eslint:
no-param-reassign
Warum? Das Manipulieren von Objekten, die als Parameter übergeben werden, kann unerwünschte Nebenwirkungen im ursprünglichen Aufrufer verursachen.
// bad
function f1(obj) {
obj.key = 1;
};
// good
function f2(obj) {
const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1;
};
- 7.13 Weise Parameter niemals neu zu. eslint:
no-param-reassign
Warum? Das Neuzuweisen von Parametern kann zu unerwartetem Verhalten führen, insbesondere beim Zugriff auf das
arguments-Objekt. Es kann auch Optimierungsprobleme verursachen, insbesondere in V8.
```javascript
// bad
function f1(a) {
a = 1;
}
function f2(a) {
if (!a) { a = 1; }
}
// good
function f3(a) {
const b = a || 1;
}
function f4(a = 1) {
}
```
Arrow-Funktionen (Arrow Functions)
- 8.1 Wenn du einen Funktionsausdruck verwenden musst (z. B. bei der Übergabe einer anonymen Funktion), verwende die Arrow-Funktionsschreibweise. eslint:
prefer-arrow-callback,arrow-spacingjscs:requireArrowFunctions
Warum? Es erstellt eine Version der Funktion, die im Kontext von
thisausgeführt wird, was normalerweise das ist, was du willst, und es ist eine prägnantere Syntax.
Warum nicht? Wenn du eine ziemlich komplexe Funktion hast, könntest du diese Logik in ihre eigene benannte Funktionsdeklaration verschieben.
// bad
[1, 2, 3].map(function (x) {
const y = x + 1;
return x * y;
});
// good
[1, 2, 3].map((x) => {
const y = x + 1;
return x * y;
});
- 8.2 Wenn der Funktionskörper aus einer einzelnen Anweisung besteht, die einen Ausdruck ohne Nebenwirkungen zurückgibt, lass die geschweiften Klammern weg und verwende die implizite Rückgabe. Behalte andernfalls die geschweiften Klammern bei und verwende eine
return-Anweisung. eslint:arrow-parens,arrow-body-stylejscs:disallowParenthesesAroundArrowParam,requireShorthandArrowFunctions
Warum? Syntaktischer Zucker (Syntactic sugar). Es ist lesbarer, wenn mehrere Funktionen miteinander verkettet sind.
Warum nicht? Wenn du vorhast, ein Objekt zurückzugeben.
// bad
[1, 2, 3].map(number => {
const nextNumber = number + 1;
`A string containing the ${nextNumber}.`;
});
// good
[1, 2, 3].map(number => `A string containing the ${number}.`);
// good
[1, 2, 3].map((number) => {
const nextNumber = number + 1;
return `A string containing the ${nextNumber}.`;
});
- 8.3 Falls sich der Ausdruck über mehrere Zeilen erstreckt, schließe ihn in Klammern ein, um die Lesbarkeit zu verbessern.
Warum? Es zeigt deutlich, wo die Funktion beginnt und endet.
// bad
[1, 2, 3].map(number => 'As time went by, the string containing the ' +
`${number} became much longer. So we needed to break it over multiple ` +
'lines.'
);
// good
[1, 2, 3].map(number => (
`As time went by, the string containing the ${number} became much ` +
'longer. So we needed to break it over multiple lines.'
));
- 8.4 Wenn deine Funktion ein einzelnes Argument annimmt und keine geschweiften Klammern verwendet, lass die Klammern weg. Füge andernfalls immer Klammern um die Argumente hinzu. eslint:
arrow-parensjscs:disallowParenthesesAroundArrowParam
Warum? Weniger visuelles Durcheinander.
// bad
[1, 2, 3].map((x) => x * x);
// good
[1, 2, 3].map(x => x * x);
// good
[1, 2, 3].map(number => (
`A long string with the ${number}. It’s so long that we’ve broken it ` +
'over multiple lines!'
));
// bad
[1, 2, 3].map(x => {
const y = x + 1;
return x * y;
});
// good
[1, 2, 3].map((x) => {
const y = x + 1;
return x * y;
});
- 8.5 Vermeide es, die Syntax der Arrow-Funktion (
=>) mit Vergleichsoperatoren (<=,>=) zu verwechseln. eslint:no-confusing-arrow
// bad
const itemHeight = item => item.height > 256 ? item.largeSize : item.smallSize;
// bad
const itemHeight = (item) => item.height > 256 ? item.largeSize : item.smallSize;
// good
const itemHeight = item => { return item.height > 256 ? item.largeSize : item.smallSize; }
Konstruktoren (Constructors)
- 9.1 Verwende immer
class. Vermeide es,prototypedirekt zu manipulieren.
Warum? Die
class-Syntax ist prägnanter und einfacher zu verstehen.
// bad
function Queue(contents = []) {
this._queue = [...contents];
}
Queue.prototype.pop = function () {
const value = this._queue[0];
this._queue.splice(0, 1);
return value;
}
// good
class Queue {
constructor(contents = []) {
this._queue = [...contents];
}
pop() {
const value = this._queue[0];
this._queue.splice(0, 1);
return value;
}
}
- 9.2 Verwende
extendsfür die Vererbung.
Warum? Es ist eine integrierte Möglichkeit, Prototyp-Funktionalität zu erben, ohne
instanceofzu beschädigen.
// bad
const inherits = require('inherits');
function PeekableQueue(contents) {
Queue.apply(this, contents);
}
inherits(PeekableQueue, Queue);
PeekableQueue.prototype.peek = function () {
return this._queue[0];
}
// good
class PeekableQueue extends Queue {
peek() {
return this._queue[0];
}
}
- 9.3 Methoden können
thiszurückgeben, um bei der Methodenverkettung (method chaining) zu helfen.
// bad
Jedi.prototype.jump = function () {
this.jumping = true;
return true;
};
Jedi.prototype.setHeight = function (height) {
this.height = height;
};
const luke = new Jedi();
luke.jump(); // => true
luke.setHeight(20); // => undefined
// good
class Jedi {
jump() {
this.jumping = true;
return this;
}
setHeight(height) {
this.height = height;
return this;
}
}
const luke = new Jedi();
luke.jump()
.setHeight(20);
- 9.4 Es ist in Ordnung, eine benutzerdefinierte toString()-Methode zu schreiben, achte nur darauf, dass sie korrekt funktioniert und keine Nebenwirkungen verursacht.
class Jedi {
constructor(options = {}) {
this.name = options.name || 'no name';
}
getName() {
return this.name;
}
toString() {
return `Jedi - ${this.getName()}`;
}
}
- 9.5 Klassen haben einen Standardkonstruktor, wenn keiner angegeben ist. Ein leerer Konstruktor oder einer, der nur an eine Elternklasse delegiert, ist unnötig.
no-useless-constructor
// bad
class Jedi {
constructor() {}
getName() {
return this.name;
}
}
// bad
class Rey extends Jedi {
constructor(...args) {
super(...args);
}
}
// good
class Rey extends Jedi {
constructor(...args) {
super(...args);
this.name = 'Rey';
}
}
Module (Modules)
- 10.1 Verwende immer Module (
import/export) über ein nicht standardmäßiges Modulsystem. Du kannst jederzeit zu deinem bevorzugten Modulsystem transpilieren.
Warum? Module sind die Zukunft, lasst uns jetzt anfangen, die Zukunft zu nutzen.
// bad
const AirbnbStyleGuide = require('./AirbnbStyleGuide');
module.exports = AirbnbStyleGuide.es6;
// ok
import AirbnbStyleGuide from './AirbnbStyleGuide';
export default AirbnbStyleGuide.es6;
// best
import { es6 } from './AirbnbStyleGuide';
export default es6;
- 10.2 Verwende keine Wildcard-Importe.
Warum? Dies stellt sicher, dass du einen einzelnen Standardexport hast.
// bad
import * as AirbnbStyleGuide from './AirbnbStyleGuide';
// good
import AirbnbStyleGuide from './AirbnbStyleGuide';
- 10.3 Und exportiere nicht direkt von einem Import.
Warum? Obwohl das Schreiben in einer Zeile prägnant ist, macht eine klare Art zu importieren und eine klare Art zu exportieren die Dinge konsistent.
// bad
// filename es6.js
export { es6 as default } from './airbnbStyleGuide';
// good
// filename es6.js
import { es6 } from './AirbnbStyleGuide';
export default es6;
Iteratoren und Generatoren (Iterators and Generators)
- 11.1 Verwende keine Iteratoren. Bevorzuge die Funktionen höherer Ordnung von JavaScript wie
map()undreduce()anstelle von Schleifen wiefor-of. eslint:no-iterator
Warum? Dies erzwingt unsere Regel der Unveränderlichkeit. Der Umgang mit reinen Funktionen, die Werte zurückgeben, ist einfacher zu verstehen als Nebenwirkungen.
eslint rules: no-iterator.
const numbers = [1, 2, 3, 4, 5];
// bad
let sum = 0;
for (let num of numbers) {
sum += num;
}
sum === 15;
// good
let sum = 0;
numbers.forEach(num => sum += num);
sum === 15;
// best (use the functional force)
const sum = numbers.reduce((total, num) => total + num, 0);
sum === 15;
- 11.2 Verwende vorerst keine Generatoren.
Warum? Sie lassen sich noch nicht gut nach ES5 transpilieren.
Eigenschaften (Properties)
- 12.1 Verwende die Punktnotation (dot notation), wenn du auf Eigenschaften zugreifst. eslint:
dot-notationjscs:requireDotNotation
const luke = {
jedi: true,
age: 28,
};
// bad
const isJedi = luke['jedi'];
// good
const isJedi = luke.jedi;
- 12.2 Verwende die Klammernotation
[], wenn du mit einer Variablen auf Eigenschaften zugreifst.
const luke = {
jedi: true,
age: 28,
};
function getProp(prop) {
return luke[prop];
}
const isJedi = getProp('jedi');
Variablen (Variables)
- 13.1 Verwende immer
constoderletum Variablen zu deklarieren. Wenn du das nicht tust, führt dies zu globalen Variablen. Wir wollen vermeiden, den globalen Namensraum (global namespace) zu verschmutzen. Captain Planet hat uns davor gewarnt.
// bad
superPower = new SuperPower();
// good
const superPower = new SuperPower();
- 13.2 Verwende eine
constoderletDeklaration pro Variable. eslint:one-varjscs:disallowMultipleVarDecl
Warum? Es ist einfacher, neue Variablendeklarationen auf diese Weise hinzuzufügen, und du musst dir keine Sorgen machen, ein
;gegen ein,auszutauschen oder nur Interpunktionsunterschiede einzuführen.
// bad
const items = getItems(),
goSportsTeam = true,
dragonball = 'z';
// bad
// (compare to above, notice the error)
const items = getItems(),
goSportsTeam = true;
dragonball = 'z';
// good
const items = getItems();
const goSportsTeam = true;
const dragonball = 'z';
- 13.3 Gruppiere alle deine
consts und dann alle deinelets.
Warum? Dies ist hilfreich, wenn du später eine Variable abhängig von einer der zuvor zugewiesenen Variablen zuweisen musst.
// bad
let i, len, dragonball,
items = getItems(),
goSportsTeam = true;
// bad
let i;
const items = getItems();
let dragonball;
const goSportsTeam = true;
let len;
// good
const goSportsTeam = true;
const items = getItems();
let dragonball;
let i;
let length;
- 13.4 Weise Variablen dort zu, wo du sie brauchst, aber platziere sie an einer vernünftigen Stelle.
Warum?
letundconstsind block-scoped und nicht function-scoped.
// bad - unnecessary function call
function checkName(hasName) {
const name = getName();
if (hasName === 'test') {
return false;
}
if (name === 'test') {
this.setName('');
return false;
}
return name;
}
// good
function checkName(hasName) {
if (hasName === 'test') {
return false;
}
const name = getName();
if (name === 'test') {
this.setName('');
return false;
}
return name;
}
Hoisting
- 14.1
var-Deklarationen werden an den Anfang ihres Gültigkeitsbereichs gehoistet, ihre Zuweisung jedoch nicht.const- undlet-Deklarationen sind mit einem neuen Konzept namens Temporal Dead Zones (TDZ) gesegnet. Es ist wichtig zu wissen, warum typeof nicht mehr sicher ist.
// we know this wouldn't work (assuming there
// is no notDefined global variable)
function example() {
console.log(notDefined); // => throws a ReferenceError
}
// creating a variable declaration after you
// reference the variable will work due to
// variable hoisting. Note: the assignment
// value of `true` is not hoisted.
function example() {
console.log(declaredButNotAssigned); // => undefined
var declaredButNotAssigned = true;
}
// The interpreter is hoisting the variable
// declaration to the top of the scope,
// which means our example could be rewritten as:
function example() {
let declaredButNotAssigned;
console.log(declaredButNotAssigned); // => undefined
declaredButNotAssigned = true;
}
// using const and let
function example() {
console.log(declaredButNotAssigned); // => throws a ReferenceError
console.log(typeof declaredButNotAssigned); // => throws a ReferenceError
const declaredButNotAssigned = true;
}
- 14.2 Anonyme Funktionsausdrücke hoisten ihren Variablennamen, aber nicht die Funktionszuweisung.
function example() {
console.log(anonymous); // => undefined
anonymous(); // => TypeError anonymous is not a function
var anonymous = function () {
console.log('anonymous function expression');
};
}
- 14.3 Benannte Funktionsausdrücke hoisten den Variablennamen, nicht den Funktionsnamen oder den Funktionskörper.
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');
};
}
// the same is true when the function name
// is the same as the variable name.
function example() {
console.log(named); // => undefined
named(); // => TypeError named is not a function
var named = function named() {
console.log('named');
}
}
- 14.4 Funktionsdeklarationen hoisten ihren Namen und den Funktionskörper.
function example() {
superPower(); // => Flying
function superPower() {
console.log('Flying');
}
}
- Für weitere Informationen siehe JavaScript Scoping & Hoisting von Ben Cherry.
Vergleichsoperatoren & Gleichheit (Comparison Operators & Equality)
-
15.1 Verwende
===und!==anstelle von==und!=. eslint:eqeqeq -
15.2 Bedingte Anweisungen wie
ifbewerten ihren Ausdruck mittels Erzwingung (coercion) mit der abstrakten MethodeToBooleanund folgen immer diesen einfachen Regeln:
- Objects werden als true ausgewertet
- Undefined wird als false ausgewertet
- Null wird als false ausgewertet
- Booleans werden als der Wert des Booleans ausgewertet
- Numbers werden als false ausgewertet, wenn +0, -0, oder NaN, sonst true
- Strings werden als false ausgewertet, wenn es ein leerer String
''ist, sonst true
if ([0] && []) {
// true
// an array (even an empty one) is an object, objects will evaluate to true
}
- 15.3 Verwende Abkürzungen.
// bad
if (name !== '') {
// ...stuff...
}
// good
if (name) {
// ...stuff...
}
// bad
if (collection.length > 0) {
// ...stuff...
}
// good
if (collection.length) {
// ...stuff...
}
- 15.4 Für weitere Informationen siehe Truth Equality and JavaScript von Angus Croll.
- 15.5 Verwende geschweifte Klammern, um Blöcke in
case- unddefault-Klauseln zu erstellen, die lexikalische Deklarationen enthalten (z. B.let,const,functionundclass).
Warum? Lexikalische Deklarationen sind im gesamten
switch-Block sichtbar, werden aber nur initialisiert, wenn sie zugewiesen werden, was nur passiert, wenn ihrcaseerreicht wird. Dies führt zu Problemen, wenn mehrerecase-Klauseln versuchen, dasselbe zu definieren.
eslint rules: no-case-declarations.
// bad
switch (foo) {
case 1:
let x = 1;
break;
case 2:
const y = 2;
break;
case 3:
function f() {}
break;
default:
class C {}
}
// good
switch (foo) {
case 1: {
let x = 1;
break;
}
case 2: {
const y = 2;
break;
}
case 3: {
function f() {}
break;
}
case 4:
bar();
break;
default: {
class C {}
}
}
- 15.7 Ternäre Operatoren sollten nicht verschachtelt werden und in der Regel einzeilige Ausdrücke sein.
eslint rules: no-nested-ternary.
// bad
const foo = maybe1 > maybe2
? "bar"
: value1 > value2 ? "baz" : null;
// better
const maybeNull = value1 > value2 ? 'baz' : null;
const foo = maybe1 > maybe2
? 'bar'
: maybeNull;
// best
const maybeNull = value1 > value2 ? 'baz' : null;
const foo = maybe1 > maybe2 ? 'bar' : maybeNull;
- 15.8 Vermeide unnötige ternäre Anweisungen.
eslint rules: no-unneeded-ternary.
// bad
const foo = a ? a : b;
const bar = c ? true : false;
const baz = c ? false : true;
// good
const foo = a || b;
const bar = !!c;
const baz = !c;
Blöcke (Blocks)
- 16.1 Verwende geschweifte Klammern bei allen mehrzeiligen Blöcken.
// bad
if (test)
return false;
// good
if (test) return false;
// good
if (test) {
return false;
}
// bad
function foo() { return false; }
// good
function bar() {
return false;
}
- 16.2 Wenn du mehrzeilige Blöcke mit
ifundelseverwendest, setzeelsein dieselbe Zeile wie die schließende geschweifte Klammer desif-Blocks. eslint:brace-stylejscs:disallowNewlineBeforeBlockStatements
// bad
if (test) {
thing1();
thing2();
}
else {
thing3();
}
// good
if (test) {
thing1();
thing2();
} else {
thing3();
}
Kontrollanweisungen (Control Statements)
- 17.1 Falls deine Kontrollanweisung (
if,whileetc.) zu lang wird oder die maximale Zeilenlänge überschreitet, kann jede (gruppierte) Bedingung in eine neue Zeile gesetzt werden. Der logische Operator sollte die Zeile beginnen.
Warum? Operatoren am Zeilenanfang zu verlangen, hält die Operatoren ausgerichtet und folgt einem ähnlichen Muster wie das Method Chaining. Dies verbessert auch die Lesbarkeit, indem es komplexe Logik visuell leichter verfolgbar macht.
// bad
if ((foo === 123 || bar === 'abc') && doesItLookGoodWhenItBecomesThatLong() && isThisReallyHappening()) {
thing1();
}
// bad
if (foo === 123 &&
bar === 'abc') {
thing1();
}
// bad
if (foo === 123
&& bar === 'abc') {
thing1();
}
// bad
if (
foo === 123 &&
bar === 'abc'
) {
thing1();
}
// good
if (
foo === 123
&& bar === 'abc'
) {
thing1();
}
// good
if (
(foo === 123 || bar === 'abc')
&& doesItLookGoodWhenItBecomesThatLong()
&& isThisReallyHappening()
) {
thing1();
}
// good
if (foo === 123 && bar === 'abc') {
thing1();
}
- 17.2 Verwende keine Auswahloperatoren anstelle von Kontrollanweisungen.
// bad
!isRunning && startRunning();
// good
if (!isRunning) {
startRunning();
}
Kommentare (Comments)
- 18.1 Verwende
/** ... */für mehrzeilige Kommentare. Füge eine Beschreibung, Spezifikationen für Typen und Werte für alle Parameter und Rückgabewerte hinzu.
// bad
// make() returns a new element
// based on the passed in tag name
//
// @param {String} tag
// @return {Element} element
function make(tag) {
// ...stuff...
return element;
}
// good
/**
* make() returns a new element
* based on the passed in tag name
*
* @param {String} tag
* @return {Element} element
*/
function make(tag) {
// ...stuff...
return element;
}
- 18.2 Verwende
//für einzeilige Kommentare. Setze einzeilige Kommentare in eine neue Zeile oberhalb des Themas des Kommentars. Füge eine Leerzeile vor dem Kommentar ein, es sei denn, er befindet sich in der ersten Zeile eines Blocks.
// bad
const active = true; // is current tab
// good
// is current tab
const active = true;
// bad
function getType() {
console.log('fetching type...');
// set the default type to 'no type'
const type = this._type || 'no type';
return type;
}
// good
function getType() {
console.log('fetching type...');
// set the default type to 'no type'
const type = this._type || 'no type';
return type;
}
// also good
function getType() {
// set the default type to 'no type'
const type = this._type || 'no type';
return type;
}
-
18.3 Das Voranstellen von
FIXMEoderTODOin deinen Kommentaren hilft anderen Entwicklern schnell zu verstehen, ob du auf ein Problem hinweist, das überdacht werden muss, oder ob du eine Lösung vorschlägst, die implementiert werden muss. Diese unterscheiden sich von regulären Kommentaren, da sie umsetzbar sind. Die Aktionen sindFIXME: -- need to figure this outoderTODO: -- need to implement. -
18.4 Verwende
// FIXME:um Probleme zu annotieren.
class Calculator extends Abacus {
constructor() {
super();
// FIXME: shouldn't use a global here
total = 0;
}
}
- 18.5 Verwende
// TODO:um Lösungen für Probleme zu annotieren.
class Calculator extends Abacus {
constructor() {
super();
// TODO: total should be configurable by an options param
this.total = 0;
}
}
Leerraum (Whitespace)
- 19.1 Verwende Soft-Tabs (Leerzeichen), die auf 2 Leerzeichen eingestellt sind. eslint:
indentjscs:validateIndentation
// bad
function foo() {
∙∙∙∙const name;
}
// bad
function bar() {
∙const name;
}
// good
function baz() {
∙∙const name;
}
- 19.2 Setze 1 Leerzeichen vor die öffnende geschweifte Klammer. eslint:
space-before-blocksjscs:requireSpaceBeforeBlockStatements
// bad
function test(){
console.log('test');
}
// good
function test() {
console.log('test');
}
// bad
dog.set('attr',{
age: '1 year',
breed: 'Bernese Mountain Dog',
});
// good
dog.set('attr', {
age: '1 year',
breed: 'Bernese Mountain Dog',
});
- 19.3 Setze 1 Leerzeichen vor die öffnende Klammer in Kontrollanweisungen (
if,whileetc.). Setze kein Leerzeichen zwischen die Argumentliste und den Funktionsnamen in Funktionsaufrufen und Deklarationen. eslint:space-after-keywords,space-before-keywordsjscs:requireSpaceAfterKeywords
// bad
if(isJedi) {
fight ();
}
// good
if (isJedi) {
fight();
}
// bad
function fight () {
console.log ('Swooosh!');
}
// good
function fight() {
console.log('Swooosh!');
}
- 19.4 Trenne Operatoren mit Leerzeichen. eslint:
space-infix-opsjscs:requireSpaceBeforeBinaryOperators,requireSpaceAfterBinaryOperators
// bad
const x=y+5;
// good
const x = y + 5;
- 19.5 Beende Dateien mit einem einzelnen Zeilenumbruch.
// bad
(function (global) {
// ...stuff...
})(this);
// bad
(function (global) {
// ...stuff...
})(this);↵
↵
// good
(function (global) {
// ...stuff...
})(this);↵
- 19.6 Verwende Einrückung bei langen Methodenverkettungen (mehr als 2 Methoden). Verwende einen führenden Punkt, der betont, dass die Zeile ein Methodenaufruf ist, keine neue Anweisung. eslint:
newline-per-chained-callno-whitespace-before-property
// bad
$('#items').find('.selected').highlight().end().find('.open').updateCount();
// bad
$('#items').
find('.selected').
highlight().
end().
find('.open').
updateCount();
// good
$('#items')
.find('.selected')
.highlight()
.end()
.find('.open')
.updateCount();
// bad
const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true)
.attr('width', (radius + margin) * 2).append('svg:g')
.attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
.call(tron.led);
// good
const leds = stage.selectAll('.led')
.data(data)
.enter().append('svg:svg')
.classed('led', true)
.attr('width', (radius + margin) * 2)
.append('svg:g')
.attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
.call(tron.led);
// good
const leds = stage.selectAll('.led').data(data);
- 19.7 Lass eine Leerzeile nach Blöcken und vor der nächsten Anweisung. jscs:
requirePaddingNewLinesAfterBlocks
// bad
if (foo) {
return bar;
}
return baz;
// good
if (foo) {
return bar;
}
return baz;
// bad
const obj = {
foo() {
},
bar() {
},
};
return obj;
// good
const obj = {
foo() {
},
bar() {
},
};
return obj;
// bad
const arr = [
function foo() {
},
function bar() {
},
];
return arr;
// good
const arr = [
function foo() {
},
function bar() {
},
];
return arr;
- 19.8 Fülle deine Blöcke nicht mit Leerzeilen auf. eslint:
padded-blocksjscs:disallowPaddingNewlinesInBlocks
// bad
function bar() {
console.log(foo);
}
// also bad
if (baz) {
console.log(qux);
} else {
console.log(foo);
}
// good
function bar() {
console.log(foo);
}
// good
if (baz) {
console.log(qux);
} else {
console.log(foo);
}
- 19.9 Füge keine Leerzeichen innerhalb von Klammern ein. eslint:
space-in-parensjscs:disallowSpacesInsideParentheses
// bad
function bar( foo ) {
return foo;
}
// good
function bar(foo) {
return foo;
}
// bad
if ( foo ) {
console.log(foo);
}
// good
if (foo) {
console.log(foo);
}
- 19.10 Füge keine Leerzeichen innerhalb von eckigen Klammern ein. eslint:
array-bracket-spacingjscs:disallowSpacesInsideArrayBrackets
// bad
const foo = [ 1, 2, 3 ];
console.log(foo[ 0 ]);
// good
const foo = [1, 2, 3];
console.log(foo[0]);
- 19.11 Füge Leerzeichen innerhalb von geschweiften Klammern ein. eslint:
object-curly-spacingjscs: [disallowSpacesInsideObjectBrackets](http://jscs.info/rule/
// bad
const foo = {clark: 'kent'};
// good
const foo = { clark: 'kent' };
- 19.12 Vermeide Zeilen mit mehr als 100 Zeichen (einschließlich Leerraum). eslint:
max-lenjscs:maximumLineLength
Warum? Dies gewährleistet Lesbarkeit und Wartbarkeit.
// bad
const foo = 'Whatever national crop flips the window. The cartoon reverts within the screw. Whatever wizard constrains a helpful ally. The counterpart ascends!';
// bad
$.ajax({ method: 'POST', url: 'https://airbnb.com/', data: { name: 'John' } }).done(() => console.log('Congratulations!')).fail(() => console.log('You have failed this city.'));
// good
const foo = 'Whatever national crop flips the window. The cartoon reverts within the screw. ' +
'Whatever wizard constrains a helpful ally. The counterpart ascends!';
// good
$.ajax({
method: 'POST',
url: 'https://airbnb.com/',
data: { name: 'John' },
})
.done(() => console.log('Congratulations!'))
.fail(() => console.log('You have failed this city.'));
Kommas (Commas)
- 20.1 Führende Kommas (Leading commas): Nein. eslint:
comma-stylejscs:requireCommaBeforeLineBreak
// bad
const story = [
once
, upon
, aTime
];
// good
const story = [
once,
upon,
aTime,
];
// bad
const hero = {
firstName: 'Ada'
, lastName: 'Lovelace'
, birthYear: 1815
, superPower: 'computers'
};
// good
const hero = {
firstName: 'Ada',
lastName: 'Lovelace',
birthYear: 1815,
superPower: 'computers',
};
- 20.2 Zusätzliches nachgestelltes Komma (Additional trailing comma): Ja. eslint:
comma-danglejscs:requireTrailingComma
Warum? Das führt zu saubereren git-Diffs. Außerdem entfernen Transpiler wie Babel das zusätzliche nachgestellte Komma im transpilierten Code, was bedeutet, dass du dir keine Sorgen um das Problem mit dem nachgestellten Komma in älteren Browsern machen musst.
// bad - git diff without trailing comma
const hero = {
firstName: 'Florence',
lastName: 'Nightingale'
+ lastName: 'Nightingale',
+ inventorOf: ['coxcomb graph', 'modern nursing']
};
// good - git diff with trailing comma
const hero = {
firstName: 'Florence',
lastName: 'Nightingale',
+ inventorOf: ['coxcomb chart', 'modern nursing'],
};
// bad
const hero = {
firstName: 'Dana',
lastName: 'Scully'
};
const heroes = [
'Batman',
'Superman'
];
// good
const hero = {
firstName: 'Dana',
lastName: 'Scully',
};
const heroes = [
'Batman',
'Superman',
];
Semikolons (Semicolons)
- 21.1 Ja. eslint:
semijscs:requireSemicolons
// bad
(function () {
const name = 'Skywalker'
return name
})()
// good
(() => {
const name = 'Skywalker';
return name;
}());
// good (guards against the function becoming an argument when two files with IIFEs are concatenated)
;(() => {
const name = 'Skywalker';
return name;
}());
Typumwandlung & Erzwingung (Type Casting & Coercion)
// => this.reviewScore = 9;
// bad
const totalScore = this.reviewScore + '';
// good
const totalScore = String(this.reviewScore);
- 22.3 Zahlen: Verwende
Numberfür die Typumwandlung undparseIntimmer mit einer Basis (radix) zum Parsen von Strings. eslint:radix
const inputValue = '4';
// bad
const val = new Number(inputValue);
// bad
const val = +inputValue;
// bad
const val = inputValue >> 0;
// bad
const val = parseInt(inputValue);
// good
const val = Number(inputValue);
// good
const val = parseInt(inputValue, 10);
- 22.4 Wenn du aus irgendeinem Grund etwas Verrücktes tust und
parseIntdein Flaschenhals ist und du Bitshift aus Leistungsgründen verwenden musst, hinterlasse einen Kommentar, der erklärt warum und was du tust.
// good
/**
* parseInt was the reason my code was slow.
* Bitshifting the String to coerce it to a
* Number made it a lot faster.
*/
const val = inputValue >> 0;
- 22.5 Hinweis: Sei vorsichtig bei der Verwendung von Bitshift-Operationen. Zahlen werden als 64-Bit-Werte dargestellt, aber Bitshift-Operationen geben immer eine 32-Bit-Ganzzahl zurück (Quelle). Bitshift kann zu unerwartetem Verhalten bei ganzzahligen Werten führen, die größer als 32 Bit sind. Diskussion. Die größte vorzeichenbehaftete 32-Bit-Ganzzahl ist 2.147.483.647:
2147483647 >> 0 //=> 2147483647
2147483648 >> 0 //=> -2147483648
2147483649 >> 0 //=> -2147483647
- 22.6 Booleans:
const age = 0;
// bad
const hasAge = new Boolean(age);
// good
const hasAge = Boolean(age);
// good
const hasAge = !!age;
Namenskonventionen (Naming Conventions)
- 23.1 Vermeide Namen mit nur einem Buchstaben. Sei beschreibend mit deiner Benennung.
// bad
function q() {
// ...stuff...
}
// good
function query() {
// ..stuff..
}
- 23.2 Verwende camelCase beim Benennen von Objekten, Funktionen und Instanzen. eslint:
camelcasejscs:requireCamelCaseOrUpperCaseIdentifiers
// bad
const OBJEcttsssss = {};
const this_is_my_object = {};
function c() {}
// good
const thisIsMyObject = {};
function thisIsMyFunction() {}
- 23.3 Verwende PascalCase nur beim Benennen von Konstruktoren oder Klassen. eslint:
new-capjscs:requireCapitalizedConstructors
// bad
function user(options) {
this.name = options.name;
}
const bad = new user({
name: 'nope',
});
// good
class User {
constructor(options) {
this.name = options.name;
}
}
const good = new User({
name: 'yup',
});
- 23.4 Verwende einen führenden Unterstrich
_beim Benennen privater Eigenschaften. eslint:no-underscore-danglejscs:disallowDanglingUnderscores
// bad
this.__firstName__ = 'Panda';
this.firstName_ = 'Panda';
// good
this._firstName = 'Panda';
- 23.5 Speichere keine Referenzen auf
this. Verwende Arrow-Funktionen oder Function#bind. jscs:disallowNodeTypes
// bad
function foo() {
const self = this;
return function () {
console.log(self);
};
}
// bad
function foo() {
const that = this;
return function () {
console.log(that);
};
}
// good
function foo() {
return () => {
console.log(this);
};
}
- 23.6 Wenn deine Datei eine einzelne Klasse exportiert, sollte dein Dateiname genau mit dem Namen deiner Klasse übereinstimmen.
// file contents
class CheckBox {
// ...
}
export default CheckBox;
// in some other file
// bad
import CheckBox from './checkBox';
// bad
import CheckBox from './check_box';
// good
import CheckBox from './CheckBox';
- 23.7 Verwende camelCase, wenn du eine Funktion als Standard exportierst. Dein Dateiname sollte identisch mit dem Namen deiner Funktion sein.
function makeStyleGuide() {
}
export default makeStyleGuide;
- 23.8 Verwende PascalCase, wenn du ein Singleton / eine Funktionsbibliothek / ein leeres Objekt exportierst.
const AirbnbStyleGuide = {
es6: {
}
};
export default AirbnbStyleGuide;
Zugriffsfunktionen (Accessors)
- 24.1 Zugriffsfunktionen für Eigenschaften sind nicht erforderlich.
- 24.2 Verwende keine JavaScript Getter/Setter, da sie unerwartete Nebenwirkungen verursachen und schwer zu testen, zu warten und zu verstehen sind. Wenn du stattdessen Zugriffsfunktionen erstellst, verwende getVal() und setVal(‘hello’).
// bad
dragon.age();
// good
dragon.getAge();
// bad
dragon.age(25);
// good
dragon.setAge(25);
- 24.3 Wenn die Eigenschaft ein Boolean ist, verwende
isVal()oderhasVal().
// bad
if (!dragon.age()) {
return false;
}
// good
if (!dragon.hasAge()) {
return false;
}
- 24.4 Es ist in Ordnung, get() und set() Funktionen zu erstellen, aber sei konsistent.
class Jedi {
constructor(options = {}) {
const lightsaber = options.lightsaber || 'blue';
this.set('lightsaber', lightsaber);
}
set(key, val) {
this[key] = val;
}
get(key) {
return this[key];
}
}
Ereignisse (Events)
- 25.1 Wenn du Datennutzlasten an Ereignisse anhängst (sei es DOM-Ereignisse oder etwas Proprietäreres wie Backbone-Ereignisse), übergebe ein Hash anstelle eines Rohwerts. Dies ermöglicht es einem nachfolgenden Mitwirkenden, weitere Daten zur Ereignisnutzlast hinzuzufügen, ohne jeden Handler für das Ereignis suchen und aktualisieren zu müssen. Zum Beispiel, anstatt:
// bad
$(this).trigger('listingUpdated', listing.id);
...
$(this).on('listingUpdated', (e, listingId) => {
// do something with listingId
});
bevorzuge:
// good
$(this).trigger('listingUpdated', { listingId: listing.id });
...
$(this).on('listingUpdated', (e, data) => {
// do something with data.listingId
});
jQuery
- 26.1 Stelle jQuery-Objekten ein
$voran. jscs:requireDollarBeforejQueryAssignment
// bad
const sidebar = $('.sidebar');
// good
const $sidebar = $('.sidebar');
// good
const $sidebarBtn = $('.sidebar-btn');
- 26.2 Scache jQuery-Suchvorgänge (Lookups).
// bad
function setSidebar() {
$('.sidebar').hide();
// ...stuff...
$('.sidebar').css({
'background-color': 'pink'
});
}
// good
function setSidebar() {
const $sidebar = $('.sidebar');
$sidebar.hide();
// ...stuff...
$sidebar.css({
'background-color': 'pink'
});
}
- 26.3 Für DOM-Abfragen verwende Cascading
$('.sidebar ul')oder parent > child$('.sidebar > ul'). jsPerf - 26.4 Verwende
findmit gescopedten jQuery-Objektabfragen.
// bad
$('ul', '.sidebar').hide();
// bad
$('.sidebar').find('ul').hide();
// good
$('.sidebar ul').hide();
// good
$('.sidebar > ul').hide();
// good
$sidebar.find('ul').hide();
ECMAScript 5 Kompatibilität (ECMAScript 5 Compatibility)
- 27.1 Siehe Kangax’s ES5 Kompatibilitätstabelle.
ECMAScript 6 Stile (ECMAScript 6 Styles)
- 28.1 Dies ist eine Sammlung von Links zu den verschiedenen Funktionen von ES6.
- Arrow Functions
- Classes
- Object Shorthand
- Object Concise
- Computed Object Properties
- Template Strings
- Destructuring
- Default Parameters
- Rest
- Array Spreads
- Let and Const
- Iterators and Generators
- Modules
Standardbibliothek (Standard Library)
Die Standardbibliothek enthält einige Dienstprogramme, die zwar kaputt sind, aber aus alten Gründen (legacy reasons) beibehalten wurden.
- 29.1 Verwende
Number.isNaNanstelle vonisNaN.
Warum?
isNaNerzwingt nicht-numerische Werte zu Zahlen und gibt true für alles zurück, was zu NaN gezwungen wird. Wenn dieses Verhalten gewünscht ist, mach es explizit.
// bad
isNaN('1.2'); // false
isNaN('1.2.3'); // true
// good
Number.isNaN('1.2.3'); // false
Number.isNaN(Number('1.2.3')); // true
- 29.2 Verwende
Number.isFiniteanstelle vonisFinite.
Warum?
isFiniteerzwingt nicht-numerische Werte zu Zahlen und gibt true für alles zurück, was zu einer endlichen Zahl gezwungen wird. Wenn dieses Verhalten gewünscht ist, mach es explizit.
// bad
isFinite('2e3'); // true
// good
Number.isFinite('2e3'); // false
Number.isFinite(parseInt('2e3', 10)); // true
Testen (Testing)
- 30.1 Ja.
function foo() {
return true;
}
- 30.2 Nein, im Ernst:
- Egal welches Test-Framework du verwendest, du solltest Tests schreiben!
- Versuche, viele kleine reine Funktionen zu schreiben und minimiere, wo Mutationen auftreten.
- Sei vorsichtig mit Stubs und Mocks - sie können deine Tests brüchiger machen.
- Wir verwenden hauptsächlich
mochabei Airbnb.tapewird auch gelegentlich für kleine, separate Module verwendet. - 100% Testabdeckung ist ein gutes Ziel, auch wenn es nicht immer praktisch zu erreichen ist.
- Wann immer du einen Bug behebst, schreibe einen Regressionstest. Ein behobener Bug ohne Regressionstest wird mit Sicherheit in Zukunft wieder kaputt gehen.
Leistung (Performance)
- On Layout & Web Performance
- String vs Array Concat
- Try/Catch Cost In a Loop
- Bang Function
- jQuery Find vs Context, Selector
- innerHTML vs textContent for script text
- Long String Concatenation
- Loading…
Ressourcen (Resources)
Lerne ES6
- Draft ECMA 2015 (ES6) Spec
- ExploringJS
- ES6 Compatibility Table
- Comprehensive Overview of ES6 Features
Pflichtlektüre
Tools
- Code Style Linters
Andere Styleguides
- Google JavaScript Style Guide
- jQuery Core Style Guidelines
- Principles of Writing Consistent, Idiomatic JavaScript
Andere Stile
- Naming this in nested functions - Christian Johansen
- Conditional Callbacks - Ross Allen
- Popular JavaScript Coding Conventions on Github - JeongHoon Byun
- Multiple var statements in JavaScript, not superfluous - Ben Alman
Weiterführende Literatur
- Understanding JavaScript Closures - Angus Croll
- Basic JavaScript for the impatient programmer - Dr. Axel Rauschmayer
- You Might Not Need jQuery - Zack Bloom & Adam Schwartz
- ES6 Features - Luke Hoban
- Frontend Guidelines - Benjamin De Cock
Bücher
- JavaScript: The Good Parts - Douglas Crockford
- JavaScript Patterns - Stoyan Stefanov
- Pro JavaScript Design Patterns - Ross Harmes and Dustin Diaz
- High Performance Web Sites: Essential Knowledge for Front-End Engineers - Steve Souders
- Maintainable JavaScript - Nicholas C. Zakas
- JavaScript Web Applications - Alex MacCaw
- Pro JavaScript Techniques - John Resig
- Smashing Node.js: JavaScript Everywhere - Guillermo Rauch
- Secrets of the JavaScript Ninja - John Resig and Bear Bibeault
- Human JavaScript - Henrik Joreteg
- Superhero.js - Kim Joar Bekkelund, Mads Mobæk, & Olav Bjorkoy
- JSBooks - Julien Bouquillon
- Third Party JavaScript - Ben Vinegar and Anton Kovalyov
- Effective JavaScript: 68 Specific Ways to Harness the Power of JavaScript - David Herman
- Eloquent JavaScript - Marijn Haverbeke
- You Don’t Know JS: ES6 & Beyond - Kyle Simpson
Blogs
- DailyJS
- JavaScript Weekly
- JavaScript, JavaScript…
- Bocoup Weblog
- Adequately Good
- NCZOnline
- Perfection Kills
- Ben Alman
- Dmitry Baranovskiy
- Dustin Diaz
- nettuts
Podcasts
In freier Wildbahn (In the Wild)
Dies ist eine Liste von Organisationen, die diesen Styleguide verwenden. Sende uns einen Pull-Request oder ein Issue, und wir fügen dich der Liste hinzu.
- Aan Zee: AanZee/javascript
- Adult Swim: adult-swim/javascript
- Airbnb: airbnb/javascript
- Apartmint: apartmint/javascript
- Avalara: avalara/javascript
- Avant: avantcredit/javascript
- Billabong: billabong/javascript
- Bisk: bisk/javascript
- Blendle: blendle/javascript
- Brainshark: brainshark/javascript
- ComparaOnline: comparaonline/javascript
- Compass Learning: compasslearning/javascript-style-guide
- DailyMotion: dailymotion/javascript
- Digitpaint digitpaint/javascript
- Ecosia: ecosia/javascript
- Evernote: evernote/javascript-style-guide
- Evolution Gaming: evolution-gaming/javascript
- ExactTarget: ExactTarget/javascript
- Expensify Expensify/Style-Guide
- Flexberry: Flexberry/javascript-style-guide
- Gawker Media: gawkermedia/javascript
- General Electric: GeneralElectric/javascript
- GoodData: gooddata/gdc-js-style
- Grooveshark: grooveshark/javascript
- How About We: howaboutwe/javascript
- Huballin: huballin/javascript
- HubSpot: HubSpot/javascript
- Hyper: hyperoslo/javascript-playbook
- InfoJobs: InfoJobs/JavaScript-Style-Guide
- Intent Media: intentmedia/javascript
- Jam3: Jam3/Javascript-Code-Conventions
- JeopardyBot: kesne/jeopardy-bot
- JSSolutions: JSSolutions/javascript
- Kinetica Solutions: kinetica/javascript
- Mighty Spring: mightyspring/javascript
- MinnPost: MinnPost/javascript
- MitocGroup: MitocGroup/javascript
- ModCloth: modcloth/javascript
- Money Advice Service: moneyadviceservice/javascript
- Muber: muber/javascript
- National Geographic: natgeo/javascript
- National Park Service: nationalparkservice/javascript
- Nimbl3: nimbl3/javascript
- Orion Health: orionhealth/javascript
- OutBoxSoft: OutBoxSoft/javascript
- Peerby: Peerby/javascript
- Razorfish: razorfish/javascript-style-guide
- reddit: reddit/styleguide/javascript
- React: /facebook/react/blob/master/CONTRIBUTING.md#style-guide
- REI: reidev/js-style-guide
- Ripple: ripple/javascript-style-guide
- SeekingAlpha: seekingalpha/javascript-style-guide
- Shutterfly: shutterfly/javascript
- Springload: springload/javascript
- StudentSphere: studentsphere/javascript
- Target: target/javascript
- TheLadders: TheLadders/javascript
- T4R Technology: T4R-Technology/javascript
- VoxFeed: VoxFeed/javascript-style-guide
- WeBox Studio: weboxstudio/javascript
- Weggo: Weggo/javascript
- Zillow: zillow/javascript
- ZocDoc: ZocDoc/javascript
Übersetzung (Translation)
Dieser Styleguide ist auch in anderen Sprachen verfügbar:
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/javacript-style-guide
Korean: tipjs/javascript-style-guide
Polish: mjurczyk/javascript
Russian: uprock/javascript
Spanish: paolocarrasco/javascript-style-guide
Vietnamese: f1remoon/javascript-style-guide
Der JavaScript Styleguide Guide (The JavaScript Style Guide Guide)
Sprich mit uns über JavaScript
- Finde uns auf gitter.
Mitwirkende (Contributors)
Lizenz (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.
Änderungen (Amendments)
Wir ermutigen dich, diesen Styleguide zu forken und die Regeln so zu ändern, dass sie zum Styleguide deines Teams passen. Unten kannst du einige Änderungen am Styleguide auflisten. Dies ermöglicht es dir, deinen Styleguide regelmäßig zu aktualisieren, ohne dich mit Merge-Konflikten (merge conflicts) auseinandersetzen zu müssen.