Featured image of post Airbnb JavaScript Styleguide

Airbnb JavaScript Styleguide

Airbnb JavaScript Styleguide

Photo by Pankaj Patel on Unsplash

https://github.com/jigsawye/javascript

Airbnb JavaScript Styleguide()

Ein größtenteils vernünftiger Ansatz für JavaScript.

Downloads Gitter

Andere Styleguides

Übersetzt von Airbnb JavaScript Style Guide.

Typen (Types)

  • 1.1 Primitive (Primitives): Auf primitive Typen wird direkt zugegriffen.
  • string
  • number
  • boolean
  • null
  • undefined
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.
  • object
  • array
  • function
const foo = [1, 2];
const bar = foo;

bar[0] = 9;

console.log(foo[0], bar[0]); // => 9, 9

Referenzen (References)

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 let anstelle von var. eslint: no-var jscs: disallowVar

Warum? let ist block-scoped, während var function-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 let als auch const block-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 = {};
// bad
const superman = {
    default: { clark: 'kent' },
    private: true,
};

// good
const superman = {
    defaults: { clark: 'kent' },
    hidden: true,
};
// 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,
};

// bad
const atom = {
    value: 1,

    addValue: function (value) {
    return atom.value + value;
    },
};

// good
const atom = {
    value: 1,

    addValue(value) {
    return atom.value + value;
    },
};

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

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)

// 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}`;
}
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)

// 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.';

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() {
}

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 Block als 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 dem arguments-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 wie arguments.

// 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() {};

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

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)

Warum? Es erstellt eine Version der Funktion, die im Kontext von this ausgefü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;
});

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.'
));

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, prototype direkt 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 extends für die Vererbung.

Warum? Es ist eine integrierte Möglichkeit, Prototyp-Funktionalität zu erben, ohne instanceof zu 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 this zurü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() und reduce() anstelle von Schleifen wie for-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)

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 const oder let um 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();

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 deine lets.

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? let und const sind 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

// 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');
    }
}

Vergleichsoperatoren & Gleichheit (Comparison Operators & Equality)

  • 15.1 Verwende === und !== anstelle von == und !=. eslint: eqeqeq

  • 15.2 Bedingte Anweisungen wie if bewerten ihren Ausdruck mittels Erzwingung (coercion) mit der abstrakten Methode ToBoolean und 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- und default-Klauseln zu erstellen, die lexikalische Deklarationen enthalten (z. B. let, const, function und class).

Warum? Lexikalische Deklarationen sind im gesamten switch-Block sichtbar, werden aber nur initialisiert, wenn sie zugewiesen werden, was nur passiert, wenn ihr case erreicht wird. Dies führt zu Problemen, wenn mehrere case-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;
}
// bad
if (test) {
    thing1();
    thing2();
}
else {
    thing3();
}

// good
if (test) {
    thing1();
    thing2();
} else {
    thing3();
}

Kontrollanweisungen (Control Statements)

  • 17.1 Falls deine Kontrollanweisung (if, while etc.) 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 FIXME oder TODO in 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 sind FIXME: -- need to figure this out oder TODO: -- 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)

// bad
function foo() {
∙∙∙∙const name;
}

// bad
function bar() {
const name;
}

// good
function baz() {
∙∙const name;
}
// 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',
});
// bad
if(isJedi) {
    fight ();
}

// good
if (isJedi) {
    fight();
}

// bad
function fight () {
    console.log ('Swooosh!');
}

// good
function fight() {
    console.log('Swooosh!');
}
// 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);
// 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);
// 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;
// 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);
}
// bad
function bar( foo ) {
    return foo;
}

// good
function bar(foo) {
    return foo;
}

// bad
if ( foo ) {
    console.log(foo);
}

// good
if (foo) {
    console.log(foo);
}
// bad
const foo = [ 1, 2, 3 ];
console.log(foo[ 0 ]);

// good
const foo = [1, 2, 3];
console.log(foo[0]);
// bad
const foo = {clark: 'kent'};

// good
const foo = { clark: 'kent' };

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)

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

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)

// 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;
}());

Lies mehr.

Typumwandlung & Erzwingung (Type Casting & Coercion)

  • 22.1 Führe die Typumwandlung am Anfang der Anweisung durch.
  • 22.2 Strings:
// => this.reviewScore = 9;

// bad
const totalScore = this.reviewScore + '';

// good
const totalScore = String(this.reviewScore);
  • 22.3 Zahlen: Verwende Number für die Typumwandlung und parseInt immer 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 parseInt dein 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
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..
}
// bad
const OBJEcttsssss = {};
const this_is_my_object = {};
function c() {}

// good
const thisIsMyObject = {};
function thisIsMyFunction() {}
// 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',
});
// 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() oder hasVal().
// 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

// 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 find mit 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)

ECMAScript 6 Stile (ECMAScript 6 Styles)

  • 28.1 Dies ist eine Sammlung von Links zu den verschiedenen Funktionen von ES6.
  1. Arrow Functions
  2. Classes
  3. Object Shorthand
  4. Object Concise
  5. Computed Object Properties
  6. Template Strings
  7. Destructuring
  8. Default Parameters
  9. Rest
  10. Array Spreads
  11. Let and Const
  12. Iterators and Generators
  13. 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.isNaN anstelle von isNaN.

Warum? isNaN erzwingt 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.isFinite anstelle von isFinite.

Warum? isFinite erzwingt 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)

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 mocha bei Airbnb. tape wird 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)

Ressourcen (Resources)

Lerne ES6

Pflichtlektüre

Tools

  • Code Style Linters

Andere Styleguides

Andere Stile

Weiterführende Literatur

Bücher

Blogs

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.

Übersetzung (Translation)

Dieser Styleguide ist auch in anderen Sprachen verfügbar:

Der JavaScript Styleguide Guide (The JavaScript Style Guide Guide)

Sprich mit uns über JavaScript

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.

Reference

All rights reserved,未經允許不得隨意轉載
Erstellt mit Hugo
Theme Stack gestaltet von Jimmy