Dies ist ein lebendiges Dokument und neue Ideen, die den Code in unserem Umfeld verbessern, sind immer willkommen. Tragt dazu bei: "fork", "clone", "branch", "commit", "push", "pull request".
- Rick Waldron @rwaldron, github
- Mathias Bynens @mathias, github
- Schalk Neethling @ossreleasefeed, github
- Kit Cambridge @kitcambridge, github
- Raynos github
- Matias Arriola @MatiasArriola, github
- John Fischer @jfroffice, github
- Idan Gazit @idangazit, github
- Leo Balter @leobalter, github
- Breno Oliveira @garu_rj, github
- Leo Beto Souza @leobetosouza, github
- Ryuichi Okumura @okuryu, github
- Pascal Precht @PascalPrecht, github
- EngForDev engfordev - Hwan Min Hong / MinTaek Kwon @leoinsight / Tw Shim @marocchino, github / Nassol Kim @nassol99, github / Juntai Park @rkJun, github / Minkyu Shim / Gangmin Won / Justin Yoo @justinchronicle / Daeyup Lee
- Marco Trulla @marcotrulla, github
Jeder Code sollte so aussehen als wenn ihn nur eine Person geschrieben hätte, völlig egal wieviele daran gearbeitet haben.
Die folgende Liste nennt die Praktiken, die sich in jeden Code den ich ursprünglich geschrieben habe wiederfinden sollten. Sämtliche Beiträge dich Ich für Projekte geleistet habe, sollten diesen Praktiken folgen.
Ich möchte nicht anderen Leuten meine Vorlieben aufzwängen; wenn es bereits einen geläufigen Style gibt, sollte das respektiert werden.
"Das es eine schlechte Idee ist, nur für sich selbst Code zu schreiben, ist etwas was man als guter Betreuer eines erfolgreichen Projektes begreifen muss™. Wenn tausende Leute deinen Code benutzen, dann schreibe deinen Code möglichst klar und übersichtlich, nicht einfach nur nach deinen persönlichen Vorlieben." - Idan Gazit
Leveraging Code Quality Tools by Anton Kovalyov
Bei den Folgenden Ressourcen sollte berücksichtigt werden das sie 1) unvollständig und 2) PFLICHTLEKTÜREN sind. Ich stimme dem geschriebenen Style der unten stehenden Autoren nicht immer zu, aber eins ist sicher: Sie sind konsequent. Außerdem sind dies echte Autoriäten in dieser Sprache.
- Baseline For Front End Developers
- Eloquent JavaScript
- JavaScript, JavaScript
- Adventures in JavaScript Development
- Perfection Kills
- Douglas Crockford's Wrrrld Wide Web
- JS Assessment
Jedes Projekt sollte Komponenten verwenden, um den Code zu linten, testen oder komprimieren, um so im Produktivbereich eingesetzt zu werden. Ben Alan hat für diese Aufgabe grunt entworfen und damit offiziell das "kits/" Verzeichnis aus diesem Repository ersetzt.
Projekte müssen irgendeine Art von Unit-, Reference, Implementation- oder Functional-Testing enthalten. Demonstrationen von Anwendungsfällen reichen als Test niht aus. Die unten aufgeführte Liste beinhaltet eine Menge nützlicher Test-Frameworks.
- Whitespace
- Schöne Syntax
- Typprüfung
- Bedingte Auswertungen
- Praktischer Style
- Bezeichnungen
- Sonstiges
- Native & Host Objekte
- Kommentare
- Einsprachiger Code
Die folgenden Bereiche zeigen einen vertretbaren Style Guide für moderne JavaScript-Entwicklung. Es handelt sich dabei aber nicht etwa um eine Art Vorschrift. Das wichtigste was man aber mitnehmen sollte ist das Gesetz der Stilkonsistenz. Egal welchen Stil du für dein Projekt wählst, er sollte als Regel betrachtet werden.
-
- Mische niemals Spaces und Tabs
- Bevor du mit einem Projekt beginnst und Code schreibst, entscheide dich zwischen Soft Intends (Spaces) oder echten Tabs.
- Für die Lesbarkeit empfehle ich die Einrückung immer auf die Größe von zwei Zeichen zu setzen. Das bedeutet zwei Spaces oder zwei Spaces repräsentieren einen echten Tab.
- Wenn dein Editor die Konfiguration "Steuerzeichen einblenden" unterstützt, solltest du sie einschalten. Das bringt folgende Vorteile mit sich:
- Erzwungene Konsistenz
- Zerstören von Whitespaces am Ende der Zeile
- Zerstören von leeren "Whitespace Zeilen"
- Commits und Diffs sind einfacher zu lesen
-
A. Leerzeichen, geschweifte Klammern und Zeilenumbrüche
// if/else/for/while/try enthalten immer Leerzeichen, geschweifte Klammern // und erstrecken sich über mehrere Zeilen // Das trägt zur Lesbarkeit bei // 2.A.1.1 // Beispiele von echt verkrampfter Syntax if(Bedingung) machWas(); while(Bedingung) iterieren++; for(var i=0;i<100;i++) irgendeineIterativeFunktion(); // 2.A.1.1 // Benutze Whitespaces um die Lesbarkeit zu verbessern if ( Bedingung ) { // statements } while ( Bedingung ) { // statements } for ( var i = 0; i < 100; i++ ) { // statements } // Noch besser: var i, length = 100; for ( i = 0; i < length; i++ ) { // statements } // Oder... var i = 0, length = 100; for ( ; i < length; i++ ) { // statements } var prop; for ( prop in object ) { // statements } if ( true ) { // statements } else { // statements }
B. Zuweisungen, Deklarationen, Funktionen (Benamte, Ausdrücke, Kontruktoren)
// 2.B.1.1 // Variablen var foo = "bar", num = 1, undef; // Literalnotationen: var array = [], object = {}; // 2.B.1.2 // Nur einmal `var` pro Scope (Funktion) zu verwenden, verbessert die Lesbarkeit // und hält deine Deklarationsliste frei von Verwirrungen // Schlecht var foo = ""; var bar = ""; var qux; // Gut var foo = "", bar = "", quux; // Oder.. var // Hier kommentieren foo = "", bar = "", quux; // 2.B.1.3 // var Statements sollten immer an den Anfang ihrers respektiven Scopes (Funktion) // Das gleiche gilt für const und let aus ECMAScript 6 // Schlecht function foo() { // irgendwas var bar = "", qux; } // Gut function foo() { var bar = "", qux; // alle Statements nach der var-Deklaration }
// 2.B.2.1 // Benannte Funktionsdeklaration function foo( arg1, argN ) { } // Benutzung foo( arg1, argN ); // 2.B.2.2 // Benannte Funktionsdeklaration function quadrat(zahl) { return zahl * zahl; } // Benutzung quadrat( 10 ); function quadrat( zahl, callback ) { callback( zahl * zahl); } quadrat( 10, function (square) { // callback Statements }); // 2.B.2.3 // Funktionsausdruck var quadrat = function ( zahl ) { // gibt irgendwas zurück return zahl * zahl; } // Functionsausdruck mit Bezeichner // Diese Form hat den Vorteil, das sie sich selbst aufrufen kann // und der Bezeichner im Stack Trace zufinden ist var factorial = function factorial( zahl ) { if ( zahl < 2 ) { return 1; } return zahl * factorial( zahl-1 ); }; // 2.B.2.4 // Konstrukturdeklaration function fooBar ( options) { this.options = options; } // Benutzung var fooBar = new FooBar({ a: "alpha" }); fooBar.options: // { a: "alpha" }
C. Ausnahmen, Leichte Abweichungen
// 2.C.1.1 // Funktionen mit Callbacks foo(function() { // Achte drauf, das es hier keinen extra Whitespace nach der ersten Klammer gibt }); // Funktionen, die ein Array erwarten, keine Whitespaces auf erster Ebene foo([ "alpha", "beta" ]); // 2.C.1.2 // Funktionen, die ein Object erwarten, haben ebenfalls keine Spaces foo({ a: "alpha", b: "beta" }); // Einzelner Stringliteral, kein Space foo("bar"); // Inner gruppierte Klammern, kein Space if ( !("foo" in obj) ) { }
D. Konsistenz gewinnt immer
In Sektion 2.A-2.C, sieht man den Vorteil durch die Verwendung von Whitespaces. Lesbarkeit und Konsistenz. Es ist immer wichtig darauf zu achten, Formatierungsvorlieben, wie der Whitespace innerhalb der Klammern, als optional zu betrachten. Trotzdem sollte sich eine Formatierung durch den ganzen Quelltext einheitlich erstrecken.
// 2.D.1.1 if (Bedingung) { // statements } while (Bedingung) { // statements } for (var i = 0; i < 100; i++) { // statements } if (true) { // statements } else { // statements }
E. Anführungszeichen
Ob du jetzt einfache oder doppelte Anführungszeichen bevorzugst ist völlig egal. JavaScript parst sie immer gleich. Das einzige worauf auf jeden Fall geachtet werden MUSS, ist Konsistenz. Vermische niemals Anführungszeichen innerhalb eines Projekts. Suche dir einen Stil aus und bleib dabei.
F. Zeilenenden und leere Zeilen
Whitespaces können diffs ruinieren. Pre-Commit-Hooks können verwendet werden, um End-Of-Line-Whitespaces zu leere Zeilen zu entfernen.
-
A. Primitive Typen
String:
typeof variable === "string"
Number:
typeof variable === "number"
Boolean:
typeof variable === "boolean"
Object:
typeof variable === "object"
Array:
Array.isArray( arrayArtigesObjekt ) (wenn möglich)
Node:
elem.nodeType === 1
null:
variable === null
null oder undefined:
variable == null
undefined:
Globale Variablen: typeof variable === "undefined" Lokale Variablen: variable === undefined Properties: object.prop === undefined object.hasOwnProperty( prop ) "prop" in object
B. Gezwungene Typen
Betrachten wir folgende Auswirkungen...
Dieses HTML ist gegeben:
<input type="text" id="foo-input" value="1">
// 3.B.1.1 // `foo` wurde mit dem Wert `0` deklariert und ist vom Typ `number` var foo = 0; // typeof foo; // "number" ... // Später im Code musst du `foo` mit einem neuen Wert aus dem input-Element überschreiben foo = document.getElementById("foo-input").value; // Wenn du jetzt mit `typeof foo` testen möchtest, wird das ergebnis `string` sein // Das bedeutet, wenn du Logik hast, die `foo` so testet: if ( foo === 1 ) { wichtigeFunktion(); } // `wichtigeFunktion()` würde niemals ausgeführt, selbst wenn `foo` den wert "1" hätte // 3.B.1.2 // Du kannst diese Probleme umgehen, indem du die Typen mit unären - order + - Operationen erzwingst: foo = +document.getElementById("foo-input".value; // ^ unärer + - Operator konvertiert den rechten Operanden in eine Zahl (Number) // typeof foo; // "number" if ( foo === 1 ) { wichtigeFunktion(); } // `wichtigeFunktion()` würde ausgeführt
Hier sind ein paar Fälle in denen Erzwingungen verwendet werden:
// 3.B.2.1 var number = 1, string = "1", bool = false; number; // 1 number + ""; // "1" string; // "1" +string; // 1 +string++; // 1 string; // 2 bool; // false +bool; // 0 bool + ""; // "false"
// 3.B.2.2 var number = 1, string = "1", bool = true; string === number; // false string === number + ""; // true +string === number; // true bool === number; // false +bool === number; // true bool === string; // false bool == !!string; // true
// 3.B.2.3 var array = [ "a", "b", "c" ]; !!~array.indexOf("a"); // true !!~array.indexOf("b"); // true !!~array.indexOf("c"); // true !!~array.indexOf("d"); // false
// 3.B.2.3 var num = 2.5; parseInt( num, 10 ); // ist das Gleiche wie... ~num; num >> 0; num >>> 0; // Gibt 2 zurück // Denke daran das negative Zahlen anders behandelt werden... var neg = -2.5; parseInt( neg, 10 ); // Ist das Gleiche wie... ~~neg; neg >> 0; // Gibt 2 zurück // Wie dem auch sei... neg >>> 0; // Gibt 4294967294 zurück
-
//4.1.1 // When du nur prüfen willst, ob ein Array eine Länge hat, ... if ( array.length > 0 ) ... // prüfe es so: if ( array.length ) ... // 4.1.2 // Wenn du nur prüfen willst, ob ein Array leer ist... if ( array.legth === 0 ) ... // mach es so: if ( !array.length ) ... // 4.1.3 // Wenn du prüfen willst ob ein String nich leer ist if ( string !== "" ) ... // ... mach es so: if ( string ) ... // 4.1.4 // Wenn du prüfen willst ob ein String leer ist... if ( string === "" ) ... // ... mach es so: if ( !string ) ... // 4.1.5 // Wenn du prüfen willst, ob eine Reference false ist... if ( foo === false ) ... // ... nutze die Negierung um eine eine true-Auswertung zu erzwingen if ( !foo ) ... // ... Sei vorsichtig, das würde auch bei 0, "", null, undefined und NaN funktionieren // Wenn du für einen boolsches false testen _musst_, mach's so: if ( foo === false ) ... // 4.1.7 // Wenn du eine Reference prüfen möchtest, die möglicherweise null oder undefined aber NICHT false... if ( foo === null || foo === undefined ) ... // ... nutze den Vorteil der Typerzwingung if ( foo == null ) ... // Denk dran, '==' wird 'null' auf 'null' UND 'undefined' matchen, aber nicht 'false', "" oder 0 null == undefined
-
// 5.1.1 // Ein praktisches Modul (function( global ) { var Module = (function() { var data = "secret"; return { // Eine boolesche Eigenschaft bool: true, // Ein Stringwert string: "a string", // Eine Array-Eigenschaft array: [ 1, 2, 3, 4 ], // Eine Objekteigenschaft object: { lang: "en-Us" }, getData: function() { // gibt den Wert von data return data; }, setData: function( value ) { // setzt den Wert von data return ( data = value ); } }; })(); // Hier könnten weitere Dinge passieren // Das Modul im globalen Namensraum verfügbar machen global.Module = Module; })( this );
// 5.2.1 // Ein praktischer Konstruktor (function( global ) { function Ctor( foo ) { this.foo = foo; return this; } Ctor.prototype.getFoo = function() { return this.foo; }; Ctor.prototype.setFoo = function( val ) { return ( this.foo = val ); }; // Um den Konstruktor ohne `new` aufzurufen, machst du möglicherweise sowas: var ctor = function( foo ) { return new Ctor( foo ); }; // Konstruktor im globalen Namensraum verfügbar machen global.ctor = ctor; })( this );
-
Du bist kein Compiler, also versuch nicht einer zu sein.
Der folgende Code ist ein Beispiel für entsetzlich schlechte Bezeichnungen:
// 6.1.1 // Beispielcode mit schlechten Bezeichnungen function q(s) { return document.querySelectorAll(s); } var i,a=[],els=q("#foo"); for(i=0;i<els.length;i++){a.push(els[i]);}
Du hast ohne Zweifel solch' einen Code geschrieben - hoffentlich hört das heute auf.
Hier ist der gleiche Code, nur klarer, durchdachter und mit einer lesbaren Struktur:
// 6.2.1 // Beispielcode mit verbesserten Bezeichnungen function query( selector ) { return document.querySelectorAll( selector ); } var idx = 0, elements = [], matches = query("#foo"), length = matches.length; for( ; idx < length; idx++ ){ elements.push( matches[ idx ] ); }
Ein paar weitere Punkte bezüglich der Bezeichnungen:
// 6.3.1 // Strings benennen `dog` ist ein String // 6.3.2 // Arrays benennen `dogs` ist ein Array bestehend aus `dog` Strings // 6.3.3 // Funktionen, Objekte, Instanzen etc. benennen camelCase; Funktions- und var- Deklarationen // 6.3.4 // Konstruktoren und Prototypen benennen PascalCase; Konstruktorfunktion // 6.3.5 // Reguläre Ausdrücke benennen rDesc = //; // 6.3.6 // Aus dem Google Closure Library Style Guide functionNamesLikeThis; variableNamesLikeThis; ConstructorNamesLikeThis; EnumNamesLikeThis; methodNamesLikeThis; SYMBOLIC_CONSTANTS_LIKE_THIS;
-
Diese Sektion stellt Ideen und Konzepte dar, die nicht dogmatisch betrachtet werden sollten. Sie sollen fragliche Praktiken fördern die immer wieder in der JavaScript Programmierung auftauchen.
A.
switch
Statemens sollten vermieden werden.Es scheint starke Verbesserungen bei der Ausführung von
switch
Statements im neuesten Firefox und Chrome zu geben. http://jsperf.com/switch-vs-object-literal-vs-module// 7.A.1.1 // Ein Beispiel Switch Statement switch( foo ) { case "alpha": alpha(); break; case "beta": beta(); break; default: // Fallback break; } // 7.A.1.2 // Besser sollte man aber ein Objektliteral oder Modul verewnden: var switchObj = { alpha: function() { // statements // a return }, beta: function() { // statements // a return }, _default: function() { // statements // a return } }; var switchModule = (function () { return { alpha: function() { // statements // a return }, beta: function() { // statements // a return }, _default: function() { // statements // a return } }; })(); // 7.A.1.3 // Wenn `foo` eine Eigenschaft von `switchObj` oder `switchModule` ist, führe diesen Code hier aus.. ( Object.hasOwnProperty.call( switchObj, foo ) && switchObj[ foo ] || switchObj._default )( args ); ( Object.hasOwnProperty.call( switchObj, foo ) && switchModule[ foo ] || switchModule._default )( args ); // Wenn du auf die Werte von `foo` vertraust und weißt was drin ist, // kannst du die ODER-Prüfung weglassen und den Code einfach nur ausführen: switchObj[ foo ]( args ); switchModule[ foo ]( args ); // Dieses Muster sorgt außerdem für Wiederverwendbarkeit von Code
B. Frühzeitige Rückgaben sorgen für lesbareren Code mit einem kleinen Performance-Unterschied
// 7.B.1.1 // Schlecht: function returnLate( foo ) { var ret; if ( foo ) { ret = "foo"; } else { ret = "quux"; } return ret; } // Gut: function returnEarly( foo ) { if ( foo ) { return "foo"; } return "quux"; }
-
Das grundsätzliche Prinzip ist hier:
Um das Ganze noch mehr zu stärken, schaue dir diese Präsentationen an:
<iframe src="http://blip.tv/play/g_Mngr6LegI.html" width="480" height="346" frameborder="0" allowfullscreen></iframe>http://blip.tv/jsconf/jsconf2011-andrew-dupont-everything-is-permitted-extending-built-ins-5211542
-
- Mehrzeilige Kommentare sind gut
- End of line comments are prohibited!
- JSDoc style is good, but requires a significant time investment
-
Programme sollten in einer Sprache geschrieben sein, egal um welche Sprache es sich handelt, wenn der Projektbetreuer diese vorgibt.
Jedes Projekt, welches dieses Dokument als grundsätzlichen Style Guide verwendet akzeptiert keine Comma-First-Formatierung, solang es nicht explizit von Projektautor angegeben wurde. Any project that cites this document as its base style guide will not accept comma first code formatting, unless explicitly specified otherwise by that project's author.