The NullDev JavaScript Styleguide
MIT License
📋 Typen
📦 Objekte
📑 Arrays
📄 Strings
📮 Modules
⤴️ Hoisting
🔲 Blocks
📝 Comments
🔻 Commas
⬇️ Accessors
🔆 Events
🔩 jQuery
🔄 ECMAScript 5 Kompartibilität
🔌 Testen
©️ Copyright
♻️ Änderungen
1.1 Primitive Typen: Bei primitiven Datentypen wird immer direkt auf deren Wert zugegriffen.
string
number
boolean
null
undefined
symbol
const foo = 1;
let bar = foo;
bar = 9;
console.log(foo, bar); // => 1, 9
1.2 Komplexe Typen: Bei komplexen Datentypen wird immer auf eine Referenz zugegriffen.
object
array
function
const foo = [1, 2];
const bar = foo;
bar[0] = 9;
console.log(foo[0], bar[0]); // => 9, 9
2.1 const
für alle Referenzen benutzen; Die Verwendung von var
vermeiden. eslint: prefer-const
, no-const-assign
Wieso? Es stellt sicher, dass man Referenzen nicht neu zuweisen kann. Das kann sonst zu Fehlern und schwer verständlichem Code führen.
// schlecht
var a = 1;
var b = 2;
// gut
const a = 1;
const b = 2;
2.2 Wenn man eine Referenz neu zuweisen muss, sollte let
an Stelle von var
benutzt werden. eslint: no-var
Wieso?
let
ist block-scoped und nicht function-scoped wievar
.
// schlecht
var count = 1;
if (true){
count += 1;
}
// gut
let count = 1;
if (true){
count += 1;
}
2.3 let
für require()
imports in NodeJS benutzen.
Wieso? Mit
const
kann man die Import-Variable später nicht neu definieren falls nötig. Außerdemn kann die Variable nicht verwendet werden, ohne sie explizit zu inizialisieren.
// schlecht
var x = require("x");
const y = require("y");
// gut
let x = require("x");
let y = require("y");
2.4 Beachten, dass let
und const
block-scoped sind.
// const und let existieren nur in dem Block, in dem sie definiert wurden.
{
let a = 1;
const b = 1;
var c = 1;
}
console.log(a); // ReferenceError: a ist nicht definiert
console.log(b); // ReferenceError: b ist nicht definiert
console.log(c); // 1
3.1 "literal syntax" für die Erstellung von Objekten benutzen. eslint: no-new-object
// schlecht
const item = new Object();
// gut
const item = {};
3.2 Automatisch berechnete Eigenschaftsnamen verwenden, wenn Objekte mit dynamischen Eigenschaftennamen erstellt werden.
Wieso? Sie erlauben es, alle Eigenschaften eines Objekts an einer Stelle zu definieren.
function getKey(k){
return `ein key mit dem Namen ${k}`;
}
// schlecht
const obj = {
id: 5,
name: "foo",
};
obj[getKey("enabled")] = true;
// gut
const obj = {
id: 5,
name: "foo",
[getKey("enabled")]: true,
};
3.3 Objekt-Methoden-Shorthands verwenden. eslint: object-shorthand
// schlecht
const foo = {
value: 1,
addValue: function (value) {
return foo.value + value;
},
};
// gut
const foo = {
value: 1,
addValue(value) {
return foo.value + value;
},
};
3.4 Eigenschaftsnamen-Shorthands benutzen. eslint: object-shorthand
Wieso? Es ist kürzer und funktionsbeschreibend.
const foo = "bar";
// schlecht
const obj = {
foo: foo,
};
// gut
const obj = {
foo,
};
3.5 Shorthand Eigenschaften am Anfang der Objekt Deklaration gruppieren.
Wieso? Man kann einfacher und schneller erkennen, welche Eigenschaften den Shorthand verwenden.
const foo = "bar";
const bar = "foo";
// schlecht
const obj = {
test: 1,
key: 2,
foo,
abc: 3,
xyz: 4,
bar,
};
// gut
const obj = {
foo,
bar,
test: 1,
key: 2,
abc: 3,
xyz: 4,
};
3.6 Nur Properties unter Anführungszeichen setzen, die invalide identifier darstellen würden. eslint: quote-props
Warum? Im Allgemeinen ist es subjektiv einfacher zu lesen. Es verbessert die Syntaxhervorhebung und wird auch von vielen JS-Engines leichter optimiert.
// schlecht
const bad = {
"foo": 3,
"bar": 4,
"data-foo": 5
};
// gut
const good = {
foo: 3,
bar: 4,
"data-foo": 5
};
3.7 Object.prototype
Methoden wie hasOwnProperty
, propertyIsEnumerable
, und isPrototypeOf
niemals direkt aufrufen. eslint: no-prototype-builtins
Warum? Diese Methoden könnten durch Eigenschaften des Ursprungsobjektes "shadowed" werden - z.B.
{ hasOwnProperty: false }
- oder, das Objekt könnte ein null-Objekt sein (Object.create(null)
).
// schlecht
object.hasOwnProperty(key);
// gut
Object.prototype.hasOwnProperty.call(object, key);
// am besten - Stage 3 Proposal:
// https://github.com/tc39/proposal-accessible-object-hasownproperty
Object.hasOwn(object, key);
3.8 Den Objekt "spread" Operator an Stelle von Object.assign
bevorzugen, um shallow-copy's von Objekten zu machen. Den Objekt "rest" Operator verwenden, um ein neues Objekt zu erzeugen, bei dem gewissen Eigenschaften weggelassen werden.
// sehr schlecht
const original = { a: 1, b: 2 };
const copy = Object.assign(original, { c: 3 }); // dies modifiziert `original`
delete copy.a; // das auch
// schlecht
const original = { a: 1, b: 2 };
const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 }
// gut
const original = { a: 1, b: 2 };
const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }
const { a, ...noA } = copy; // noA => { b: 2, c: 3 }