Der Stil, den Sie für Ihr Projekt wählen, sollte den höchsten Standards entsprechen. Platzieren Sie es als Beschreibung in Ihrem Projekt und verlinken Sie es auf dieses Dokument, um die Konsistenz, Lesbarkeit und Wartbarkeit des Codestils zu gewährleisten.
1. Leer
1. Mischen Sie niemals Leerzeichen und Tabulatoren.
2. Starten Sie ein Projekt und wählen Sie vor dem Schreiben von Code die weiche Einrückung (Leerzeichen) oder die Tabulatortaste (als Einrückungsmethode) und verwenden Sie diese als oberste Richtlinie.
a) Zur besseren Lesbarkeit empfehle ich immer, in Ihren Editoren Einzüge mit einer Breite von zwei Buchstaben zu entwerfen – das entspricht zwei Leerzeichen oder zwei Leerzeichen anstelle eines Tabulators.
3. Wenn Ihr Editor dies unterstützt, aktivieren Sie bitte immer die Einstellung „Unsichtbare Zeichen anzeigen“. Die Vorteile sind:
a) Stellen Sie die Konsistenz sicher
b). Entfernen Sie Leerzeichen in leeren Zeilen
d). >
A. Klammern, geschweifte Klammern, Zeilenumbrüche
if(condition) doSomething();
while(condition) iterating ;
for(var i=0;i<100;i ) someIterativeFn();
// 2.A.1.1
// Verwenden Sie Leerzeichen, um die Lesbarkeit zu verbessern
if (condition) {
}
while (condition) {
}
for ( var i = 0; i < 100; i ) {
}
// Besserer Ansatz:
var i,
length = 100;
for ( i = 0; i < length; i ) {
}
// Oder...
var i = 0,
length = 100;
für ( ; i < Länge; i ) {
}
var prop;
for ( prop in object ) {
// Statement}
if ( true ) {
} else {
// Statement
}
B. Zuweisung, Deklaration, Funktion (benannte Funktion, Funktionsausdruck, Konstruktorfunktion)
object = {};
// 2.B.1.2
// und sorgt für Ordnung in Ihrer Deklarationsliste (erspart Ihnen außerdem ein paar Tastenanschläge)
// Schlecht
var bar = "";
var qux;
// OK
bar = "",
quux;
// Oder..
foo = "",
bar = "",
quux;
// 2.B.1.3
// Funktioniert auch mit Konstanten aus ECMAScript 6
// Schlechte
// Vor der Variablen
var bar = "",
qux;}
// OK
var bar = "",
qux;
// Alle Anweisungen stehen nach Variablen
// 2.B.2.1
// Benannte Funktionsdeklaration
function foo( arg1, argN ) {
}
// Verwendung
foo( arg1, argN );
// 2.B.2.2
Funktionsquadrat( Zahl) {
Rückgabenummer * Zahl;
}
// So verwenden Sie
// Sehr unnatürlicher Fortsetzungsübergabestil
Funktionsquadrat( Zahl, Rückruf) {
}
square( 10, function( quadrat ) {
// Rückrufinhalt
// 2.B.2.3
// Funktionsausdruck
// Wertvollen und relevanten Inhalt zurückgeben
return number * number; ;
// Funktionsausdruck mit Bezeichner
// Diese bevorzugte Form verfügt über zusätzliche Funktionalität, die es ihr ermöglicht, sich selbst aufzurufen
// und hat den Bezeichner auf dem Stapel
if ( number < 2 ) {
return 1;
}
Rückgabenummer * Fakultät( Zahl-1 );
};
// Konstruktordeklaration
function FooBar( options ) {
this.options = Optionen;
}
var fooBar = new FooBar({ a: "alpha" });
// { a: "alpha" }
C. Ausnahmen, Details
Code kopieren
// Die Funktion akzeptiert „array“ als Parameter, keine Leerzeichen
foo([ "alpha", "beta" ]);
// 2.C.1.2
// Die Funktion akzeptiert „Objekt“ als Parameter, keine Leerzeichen
foo({
a: „alpha“,
b: „beta“
});
// Die Funktion akzeptiert das Literal „string“ als Parameter, keine Leerzeichen
foo("bar");
//Es gibt keine Leerzeichen innerhalb der Klammern, die für die Gruppierung verwendet werden
if ( !("foo" in obj) ) {
}
In den Abschnitten 2.A-2.C wird Leerraum als empfohlener Ansatz vorgeschlagen, der auf einem einfachen, höheren Zweck basiert: Einheit. Es ist zu beachten, dass Formatierungseinstellungen wie „interner Leerraum“ optional sein müssen, aber im Quellcode des gesamten Projekts nur ein Typ vorhanden sein darf.
if (condition) {
// Statement
}
while (condition) {
// Statement
}
for (var i = 0; i < 100; i ) {
// Aussage
}
if (true) {
// Statement
} else {
// Statement
}
Es spielt keine Rolle, ob Sie einfache oder doppelte Anführungszeichen wählen, sie machen beim Parsen in JavaScript keinen Unterschied. Was unbedingt durchgesetzt werden muss, ist Konsistenz. Mischen Sie niemals zwei Arten von Angeboten im selben Projekt, wählen Sie eine aus und bleiben Sie konsistent.
F. Zeilenende und Leerzeile
Das Belassen von Leerzeichen zerstört die Unterscheidung und macht die Verwendung von Änderungen unleserlich. Erwägen Sie die Einbindung eines Pre-Commit-Hooks, um Leerzeichen am Zeilenende und in Leerzeilen automatisch zu entfernen.
3. Typerkennung (aus den jQuery Core Style Guidelines)
A. Direkte Typen (tatsächliche Typen, tatsächliche Typen)
String:
Globale Variablen:
Bedenken Sie die Bedeutung davon...
Gegebenes HTML:
// 3.B.1.1
// `foo` wurde der Wert `0` zugewiesen und der Typ ist `number`
var foo = 0;
// typeof foo;
// "number"
...
// Im nachfolgenden Code müssen Sie „foo“ aktualisieren, um den neuen Wert anzugeben, der im Eingabeelement
erhalten wurdefoo = document.getElementById("foo-input").value;
// Wenn Sie jetzt „typeof foo“ testen, ist das Ergebnis „string“
// Das bedeutet, dass Ihre if-Anweisung zum Erkennen von „foo“ eine ähnliche Logik wie diese hat:
if ( foo === 1 ) {
importantTask();
}
// `importantTask()` wird niemals ausgeführt, auch wenn `foo` den Wert „1“ hat
// 3.B.1.2
// Sie können den unären Operator / - geschickt verwenden, um den Typ umzuwandeln und das Problem zu lösen:
foo = document.getElementById("foo-input").value;
// ^ Der unäre Operator wandelt den Operanden auf seiner rechten Seite in „Zahl“ um
// typeof foo;
// "number"
if ( foo === 1 ) {
importantTask();
}
// `importantTask()` wird aufgerufen
var number = 1,
string = "1",
bool = false;
Nummer;
// 1
Nummer "";
// "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
// Es ist erwähnenswert, dass die oben genannten Dinge „unnötig clever“ sind.
// Verwenden Sie eine klare Lösung, um die zurückgegebenen Werte zu vergleichen.
// Wie zum Beispiel indexOf:
if ( array.indexOf( "a" ) >= 0 ) {
// ...
}
// 3.B.2.3
var num = 2,5;
parseInt( num, 10 );
// Entspricht...
~~num;
num >> 0;
num >>> 0;
//Das Ergebnis ist immer 2
// Denken Sie immer daran, dass negative Werte unterschiedlich behandelt werden...
var neg = -2,5;
parseInt( neg, 10 );
// Entspricht...
~~neg;
neg >> 0;
// Das Ergebnis ist immer -2
// Aber...
neg >>> 0;
//Das Ergebnis ist 4294967294
4. Vergleichsvorgang
// ...Um die Authentizität zu bestimmen, verwenden Sie bitte Folgendes:
if (array.length) ...
// 4.1.2
// Wenn Sie nur beurteilen, ob ein Array leer ist, verwenden Sie stattdessen Folgendes:
if (array.length === 0) ...
// ...Um die Authentizität zu bestimmen, verwenden Sie bitte Folgendes:
if ( !array.length ) ...
// 4.1.3
// Wenn Sie nur beurteilen, ob eine Zeichenfolge leer ist, verwenden Sie stattdessen Folgendes:
if ( string !== "" ) ...
// ...Um die Authentizität zu bestimmen, verwenden Sie bitte Folgendes:
if ( string ) ...
// 4.1.4
// Wenn Sie nur beurteilen, ob eine Zeichenfolge leer ist, verwenden Sie stattdessen Folgendes:
if ( string === "" ) ...
// ...Um die Authentizität zu bestimmen, verwenden Sie bitte Folgendes:
if ( !string ) ...
// 4.1.5
// Wenn Sie nur beurteilen, ob eine Referenz wahr ist, verwenden Sie stattdessen Folgendes:
if ( foo === true ) ...
// ... Beurteilen Sie genau so, wie Sie denken, und genießen Sie die Vorteile der integrierten Funktionen:
if ( foo ) ...
// 4.1.6
// Wenn Sie nur beurteilen, ob eine Referenz falsch ist, verwenden Sie stattdessen Folgendes:
if ( foo === false ) ...
// ...konvertieren Sie es mithilfe eines Ausrufezeichens in „true“
if ( !foo ) ...
// ...Es sollte beachtet werden, dass: dies mit 0, "", null, undefiniert, NaN übereinstimmt
// Wenn Sie vom booleschen Typ „false“ sein _müssen_, verwenden Sie es bitte wie folgt:
if ( foo === false ) ...
// 4.1.7
// Wenn Sie eine Referenz berechnen möchten, kann diese null oder undefiniert sein, aber sie ist nicht falsch, „“ oder 0,
// Anstatt dies zu verwenden:
if ( foo === null || foo === undefiniert ) ...
// ...genießen Sie die Vorteile der Typumwandlung ==, so:
if ( foo == null ) ...
// Denken Sie daran, dass die Verwendung von == dafür sorgt, dass „null“ mit „null“ und „undefiniert“ übereinstimmt
//, aber nicht mit „false“, „“ oder 0
null == undefiniert
Beurteilen Sie immer den besten und genauesten Wert. Das Obige ist eine Richtlinie und kein Dogma.
// `===` zuerst, `==` zweitens (es sei denn, ein lose getippter Vergleich ist erforderlich)
// `===` führt nie eine Typkonvertierung durch, was bedeutet:
"1" === 1;
// false
// `==` konvertiert den Typ, was bedeutet:
"1" == 1;
// true
// 4.2.2
// Boolean, True & False
// Boolean:
wahr, falsch
// True:
"foo", 1
// Pseudo:
"", 0, null, undefiniert, NaN, void 0
5. Praktischer Stil
(function( global ) {
var Module = (function() {
var data = "secret";
return {
// Dies ist ein boolescher Wert
bool: true,
// Ein String
string: "a string",
// Ein Array
Array : [ 1, 2, 3, 4 ],
// Ein Objekt
object: {
lang: "en-Us"
},
getData: function() {
. data = value );
}
};
})();
// Einige andere werden hier erscheinen
// Verwandeln Sie Ihr Modul in ein globales Objekt
global.Module = Module;
})( this );
// 5.2.1
// Eine praktische Konstruktionsfunktion
(function( global ) {
Funktion Ctor( foo ) {
gib dies zurück;
}
Ctor.prototype.getFoo = function() {
return this.foo; };
return ( this.foo = val );
};
var ctor = function( foo ) {
return new Ctor( foo );
};
// Verwandeln Sie unseren Konstruktor in ein globales Objekt
global.ctor = ctor;
})( this );
6. Benennung
A. Sie sind kein menschlicher Compiler/Kompressor, also versuchen Sie, einer zu werden.
Der folgende Code ist ein Beispiel für eine extrem schlechte Benennung:
function q(s) {
return document.querySelectorAll(s);
}
var i,a=[],els=q("#foo");
for( i=0;i
Kein Zweifel, Sie haben solchen Code geschrieben – ich hoffe, dass er ab heute nie wieder auftauchen wird.
Hier ist ein Code für die gleiche Logik, aber mit robusterer und passenderer Benennung (und einer lesbareren Struktur):
Funktion query( selector ) {
return document.querySelectorAll( selector );
}
var idx = 0,
elements = [],
matches = query("#foo"),
length = matches.length;
for ( ; idx < length; idx ) {
elements.push( matches[ idx ] );
}
`dog` ist eine Zeichenfolge
// 6.A.3.2
// Benannte Arrays
`['dogs']` ist ein Array
, das die Zeichenfolge „dog“ enthält// 6.A.3.3
// Benannte Funktionen, Objekte, Instanzen usw.
camlCase; Funktions- und Variablendeklaration
// 6.A.3.4
// Benannte Erbauer, Prototypen usw.
PascalCase; Konstruktorfunktion
// 6.A.3.5
// Benannte reguläre Ausdrücke
rDesc = //;
// 6.A.3.6
// Aus dem Google Closure Library Style Guide
functionNamesLikeThis;
variableNamesLikeThis;
ConstructorNamesLikeThis;
EnumNamesLikeThis;
methodNamesLikeThis;
SYMBOLIC_CONSTANTS_LIKE_THIS;
Bevorzugen Sie zusätzlich zur Verwendung des bekannten Aufrufs und Anwendens immer .bind( this ) oder ein funktionales Äquivalent dazu. Erstellen Sie eine BoundFunction-Deklaration für nachfolgende Aufrufe und verwenden Sie Aliase nur dann, wenn es keine bessere Alternative gibt.
this.value = null;
// Erstelle einen neuen asynchronen Stream, der kontinuierlich aufgerufen wird
stream.read( opts.path, function( data ) {
// Stream verwenden, um den neuesten Datenwert zurückzugeben und den Wert der Instanz zu aktualisieren
this.value = data;
}.bind(this) );
// Kontrolliere die Häufigkeit der Ereignisauslösung
setInterval(function() {
// Ein kontrolliertes Ereignis ausgeben
this.emit("event");
}.bind(this), opts.freq || 100 );
}
// Angenommen, wir haben den Ereignisemitter (EventEmitter) geerbt ;)
Wenn das nicht funktioniert, steht in den meisten modernen JavaScript-Bibliotheken eine .bind-äquivalente Funktionalität zur Verfügung.
// Beispiel: lodash/underscore, _.bind()
function Device( opts ) {
this.value = null;
stream.read( opts.path, _.bind(function( data ) {
this.value = data;
}, this) );
setInterval(_.bind(function() {
this.emit("event");
}, this), opts.freq || 100 );
}
// Beispiel: jQuery.proxy
function Device( opts ) {
this.value = null;
stream.read( opts.path, jQuery.proxy(function( data ) {
this.value = data;
}, this) );
setInterval( jQuery.proxy(function() {
this.emit("event");
}, this), opts.freq || 100 );
}
// Beispiel: dojo.hitch
function Device( opts ) {
this.value = null;
stream.read( opts.path, dojo.hitch( this, function( data ) {
this.value = data;
}) );
setInterval( dojo.hitch( this, function() {
this.emit("event");
}), opts.freq ||. 100 );
}
function Device( opts ) {
var self = this;
this.value = null;
stream.read( opts.path, function( data ) {
self.value = data;
});
setInterval(function() {
self.emit("event");
}, opts.freq ||. 100 );
}
C. Verwenden Sie thisArg
Mehrere Prototypmethoden in ES 5.1 verfügen über ein spezielles thisArg-Tag. Verwenden Sie es so oft wie möglich
var obj;
obj = { f: "foo", b: "bar", q: "qux" };
Object.keys( obj ).forEach(function( key ) {
// |this|. ist jetzt „obj“
console.log( this[ key ] );
}, obj ); // <-- Der letzte Parameter ist `thisArg`
//Drucken Sie es aus...
// "foo"
// "bar"
// "qux"
7. Sonstiges
Die Ideen und Konzepte, die in diesem Abschnitt erläutert werden, sind keine Dogmen. Stattdessen wird die Neugier auf bestehende Praktiken geweckt, um zu versuchen, bessere Lösungen für allgemeine JavaScript-Programmieraufgaben bereitzustellen.
A. Vermeiden Sie die Verwendung von Schaltern, da die moderne Methodenverfolgung Funktionen mit Schalterausdrücken auf die schwarze Liste setzt.
Es scheint, dass die Switch-Anweisungen in den neuesten Versionen von Firefox und Chrome erheblich verbessert wurden. http://jsperf.com/switch-vs-object-literal-vs-module
Es ist erwähnenswert, dass die Verbesserungen hier zu sehen sind: https://github.com/rwldrn/idiomatic.js/issues/13
switch( foo ) {
case "alpha":
alpha();
break;
case "beta":
beta();
break;
default:
//Standardzweig
break;
}
// 7.A.1.2
// Eine Möglichkeit, Komposition und Wiederverwendung zu unterstützen, besteht darin, ein Objekt zum Speichern von „Fällen“ zu verwenden.
// Verwenden Sie eine Funktion zum Delegieren:
Var-Fälle, Delegator;
// Rückgabewert dient nur zur Veranschaulichung
cases = {
alpha: function() {
// Anweisung
// Ein Rückgabewert
return [ "Alpha", Argumente .length ];
},
beta: function() {
// Statement
// Ein Rückgabewert
return [ "Beta", arguments.length ];
} ,
_default: function() {
// Statement
// Ein Rückgabewert
return [ "Default", arguments.length ];
}
};
delegator = function() {
var args, key, delegate;
// „Argument“ in ein Array konvertieren
args = [].slice.call( arguments );
// Den ersten Wert aus „argument“ extrahieren
key = args.shift();
// Rufen Sie den Standardzweig auf
Delegate = Cases._default;
// Methoden vom Objekt delegieren
if ( case.hasOwnProperty( key ) ) {
delegate = case[ key ];
}
// Der Gültigkeitsbereich von arg kann auf einen bestimmten Wert festgelegt werden,
// In diesem Fall ist |null| in Ordnung
return delegate.apply( null, args );
};
// 7.A.1.3
// Verwendung der API in 7.A.1.2:
delegator( "alpha", 1, 2, 3, 4, 5 );
// [ "Alpha", 5 ]
// Natürlich kann der Wert des Schlüssels „case“ leicht in einen beliebigen Wert geändert werden
var caseKey, someUserInput;
// Ist es möglich, dass es sich um irgendeine Form der Eingabe handelt?
someUserInput = 9;
if ( someUserInput > 10 ) {
caseKey = "alpha";
} else {
caseKey = "beta";
}
// Oder...
caseKey = someUserInput > 10 ? "alpha" : "beta";
// Dann...
delegator( caseKey, someUserInput );
// [ "Beta", 1 ]
// Natürlich kannst du es auch so machen...
delegator();
// [ "Default", 0 ]
B. Die frühzeitige Rückgabe des Werts verbessert die Lesbarkeit des Codes ohne großen Leistungsunterschied
if ( foo ) {
ret = "foo";
} else {
ret = "quux";
}
return ret;
}
// OK:
Funktion returnEarly( foo ) {
if ( foo ) {
return „foo“;
}
return „quux“;
}
8. Native & Host-Objekte (Hinweis: Tatsächlich war ich immer der Meinung, dass Host-Objekte nicht übersetzt werden sollten, deshalb werde ich es so übersetzen, wie es in gewöhnlichen Büchern geschrieben steht)
Das grundlegendste Prinzip ist:
Machen Sie keine Dummheiten, sonst wird alles besser.
Um diese Idee zu untermauern, schauen Sie sich diese Demo an:
„Alles ist erlaubt: Native Erweiterungen“ von Andrew Dupont (JSConf2011, Portland, Oregon)
http://blip.tv/jsconf/jsconf2011-andrew-dupont-everything-is-permitted-extending-built-ins-5211542
9. Notizen
Einzeilige Kommentare, die oberhalb des Codes platziert werden, werden bevorzugt.
Mehrzeilige Kommentare sind ebenfalls möglich.
Kommentare am Zeilenende sollten vermieden werden!
Die JSDoc-Methode ist auch gut, benötigt aber mehr Zeit.
10. Verwenden Sie eine Sprache
Programme sollten nur in derselben Sprache geschrieben werden, unabhängig von der vom Programmbetreuer (oder Team) angegebenen Sprache.
Anhang
Komma zuerst
Alle Projekte, die dieses Dokument als grundlegenden Styleguide verwenden, erlauben keine Codeformatierung mit führenden Kommas, es sei denn, dies wird vom Autor ausdrücklich angegeben oder angefordert.