Acesta este un document în continuă dezvoltare și noi idei pentru îmbunătățirea codului pe care-l scriem sunt întotdeauna binevenite. Contribuie și tu: 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
- Alex Navasardyan @alexnavasardyan, github
- Mihai Paun @mihaipaun, github
- Evgeny Mandrikov @_godin_, github
- Sofish Lin @sofish, github
- Дејан Димић @dejan_dimic, github
- Miloš Gavrilović @gavrisimo, github
- Duc Nguyen @ducntq, github
- James Young @jamsyoung, github
- Stephane Moreau github
- Boris Nekezov github
- Akshat Joshi @akshat_joshi, github
Tot codul dintr-o aplicație trebuie să arate ca și cum ar fi fost scris de o singură persoană, indiferent de câți oameni au contribuit la scrierea lui.
Următoarea listă subliniază practicile pe care le folosesc în aplicațiile al căror autor original sunt; contribuțiile la proiectele pe care le-am creat ar trebui să urmeze aceste indicații.
Nu intenționez să impun preferințele mele de stilizare a codului altor oameni sau proiecte; în cazul în care un stil comun există, ar trebui respectat.
"Dezbaterile asupra stilizării sunt inutile. Ar trebui să existe un ghid de stilizare, şi ar trebui urmat"
Rebecca Murphey
"Una din condițiile pentru a fi un bun administrator al unui proiect de succes este realizarea faptului că a scrie cod pentru tine este o IDEE REA™. Dacă mii de oameni îți folosesc codul, atunci scrie cod pentru claritate maximă, nu după preferințele personale de a deveni expert în specificații."
Idan Gazit
- ORIGINAL
- Bulgarian
- German
- French
- Spanish
- Portuguese - Brazil
- Korean
- Japanese
- Italian
- Russian
- Romanian
- 简体中文
- Serbian - cyrilic alphabet
- Serbian - latin aplphabet
- Greek
- Hindi
Următoarele ar trebui să fie considerate 1) incomplete, și 2) LECTURĂ OBLIGATORIE. Nu sunt întotdeauna de acord cu stilul promovat de următorii autori, dar un lucru este clar: Sunt consecvenți. Mai mult decât atât, ei reprezintă autorități ale limbajului.
- Baseline For Front End Developers
- Eloquent JavaScript
- JavaScript, JavaScript
- Adventures in JavaScript Development
- Perfection Kills
- Douglas Crockford's Wrrrld Wide Web
- JS Assessment
- Leveraging Code Quality Tools by Anton Kovalyov
Proiectele ar trebui să încerce mereu să includă unele mijloace prin care sursele pot fi validate (linted), testate și comprimate în vederea pregătirii pentru producție. Pentru această activitate, grunt de Ben Alman este principala opțiune și a înlocuit oficial directorul "kits/" al acestui repozitoriu.
Proiectele trebuie să includă o formă sau alta de testare unitară, de referință, de implementare sau funcțională. Studiile de caz NU SE CONSIDERĂ "teste". Lista următoare este o listă de framework-uri de testare, niciunul dintre ele nefiind mai avizat decât celălalt.
- Spațiile albe
- Sintaxă plăcută
- Verificarea tipului (Curtoazie a indicațiilor stilistice din jQuery Core)
- Evaluare condițională
- Stil practic
- Nomenclatura
- Diverse
- Obiecte native și gazdă
- Comentarii
- Un cod, un limbaj
Următoarele secțiuni subliniază un ghid de stilizare rezonabil pentru dezvoltarea modernă de cod JavaScript și nu sunt menite să fie normative. Cea mai importantă de reținut este legea coerenței stilului de cod. Orice stil ai considera pentru proiectul tău trebuie considerat lege. Consideră acest document ca o declarație a consistenței, lizibilității și mentenabilității proiectului tău.
- Nu se amestecă spațiile albe cu taburile.
- La începutul unui proiect, înainte de a începe să scrii cod, alege între spațiere soft (spații) sau taburi - consideră aceasta lege.
- Pentru lizibilitate, recomand configurarea setării de indentare a editorului la 2 caractere — asta înseamnă două spații sau două spații reprezentând un tab real.
- Dacă editorul suportă, opțiunea "show invisibles" ar trebui să fie bifată. Beneficiile acestei practici sunt:
- Consecvență aplicată
- Eliminarea spațiilor albe de la sfîrșitul liniei
- Eliminarea rândurilor libere
- Commit-urile și diff-urile sunt mai ușor de citit
-
A. Parantezele, Acoladele, Liniile noi
// if/else/for/while/try au întotdeauna spații, acolade și se întind pe mai multe linii // asta încurajează lizibilitatea codului // 2.A.1.1 // Exemple de sintaxă foarte înghesuită if(condition) doSomething(); while(condition) iterating++; for(var i=0;i<100;i++) someIterativeFn(); // 2.A.1.1 // Folosește spațiere pentru a încuraja lizibilitatea codului if ( condition ) { // declarații } while ( condition ) { // declarații } for ( var i = 0; i < 100; i++ ) { // declarații } // De preferat: var i, length = 100; for ( i = 0; i < length; i++ ) { // declarații } // Sau... var i = 0, length = 100; for ( ; i < length; i++ ) { // declarații } var prop; for ( prop in object ) { // declarații } if ( true ) { // declarații } else { // declarații }
B. Atribuiri, Declarații, Funcții ( Nomenclatura, Expresie, Constructor )
// 2.B.1.1 // Variabile var foo = "bar", num = 1, undef; // Notații literale: var array = [], object = {}; // 2.B.1.2 // Folosirea unei singure `var` per context (funcție) încurajează lizibilitatea codului // și păstrează lista declarațiilor în ordine (de asemenea te scutește de câteva tastări) // Incorect var foo = ""; var bar = ""; var qux; // Corect var foo = "", bar = "", quux; // sau.. var // Comentarii foo = "", bar = "", quux; // 2.B.1.3 // declarațiile de variable trebuie să fie la începutul contextului lor respectiv (funcției). // Același lucru se aplică pentru const și let din ECMAScript 6. // Incorect function foo() { // unele declarații aici var bar = "", qux; } // Corect function foo() { var bar = "", qux; // restul codului după declarațiile de variabile }
// 2.B.2.1 // Declarație de funcție denumită function foo( arg1, argN ) { } // Utilizare foo( arg1, argN ); // 2.B.2.2 // Declarație de funcție denumită function square( number ) { return number * number; } // Utilizare square( 10 ); // Stil foarte artificial de transmitere a continuității function square( number, callback ) { callback( number * number ); } square( 10, function( square ) { // declarații callback }); // 2.B.2.3 // Exprimarea Funcției var square = function( number ) { // returnează ceva valoros și relevant return number * number; }; // Exprimarea Funcției și Identificator // Această formă preferată are valoarea adăugată de a fi // capabilă de a se invoca și de a avea o identitate în stiva de comenzi var factorial = function factorial( number ) { if ( number < 2 ) { return 1; } return number * factorial( number-1 ); }; // 2.B.2.4 // Declarația Constructor-ului function FooBar( options ) { this.options = options; } // Utilizare var fooBar = new FooBar({ a: "alpha" }); fooBar.options; // { a: "alpha" }
C. Excepții, Ușoare Abateri
// 2.C.1.1 // Funcții cu callbacks foo(function() { // De observat că nu există spațiu intre prima paranteză // a funcției în execuție și cuvântul "function" }); // Funcție care primește ca parametru un array, fără spații foo([ "alpha", "beta" ]); // 2.C.1.2 // Funcție care primește ca paremtru un obiect, fără spații foo({ a: "alpha", b: "beta" }); // Un singur argument literal de tip string, fără spații foo("bar"); // Paranteze interioare grupate, fără spații if ( !("foo" in obj) ) { }
D. Consecvența are câștig de cauză întotdeauna
În secțiunile 2.A-2.C, normele de spațiere sunt stabilite drept o recomandare cu un scop simplu și precis: consecvența. E important de reținut că preferințele de formatare, precum "spațierea interioară" ar trebui să fie considerate opționale, dar un singur stil ar trebui să existe pe întreaga sursă a proiectului.
// 2.D.1.1 if (condition) { // declarații } while (condition) { // declarații } for (var i = 0; i < 100; i++) { // declarații } if (true) { // declarații } else { // declarații }
E. Ghilimele
Fie că preferi ghilimele simple sau duble nu ar trebui să conteze, nu există o diferență în modul de parsare al JavaScript. Ce trebuie NEAPĂRAT FĂCUT este să primeze consecvența. Nu amesteca tipul de ghilimele în același proiect. Alege un stil și ține-te de el.
F. Sfîrșitul de Linii și Liniile Goale
Spațiile albe pot distruge diff-urile și pot randa modificările imposibil de citit. Ia în calcul incorporarea unui hook pre-commit care elimină automat spațiile albe de la sfîrșitul liniilor și spațiile goale de pe liniile libere.
-
Verificarea tipului (Curtoazie a indicațiilor stilistice din jQuery Core)
A. Tipuri Existente
String:
typeof variable === "string"
Number:
typeof variable === "number"
Boolean:
typeof variable === "boolean"
Object:
typeof variable === "object"
Array:
Array.isArray( arrayLikeObject ) (ori de câte ori este posibil)
Node:
elem.nodeType === 1
null:
variable === null
null sau undefined:
variable == null
undefined:
Variabile Globale:
typeof variable === "undefined"
Variabile Locale:
variable === undefined
Proprietăți:
object.prop === undefined object.hasOwnProperty( prop ) "prop" in object
B. Tipuri Constrânse
Luați în considerare implicațiile următoarelor...
Dat fiind codul HTML:
<input type="text" id="foo-input" value="1">
// 3.B.1.1 // `foo` a fost declarat cu valoarea `0` și este de tipul `number` var foo = 0; // typeof foo; // "number" ... // Ulterior, trebuie actualizată variabila `foo` // cu o nouă valoare derivată dintr-un element `input` foo = document.getElementById("foo-input").value; // Dacă ar fi să verificați `typeof foo` acum, rezultatul ar fi `string` // Asta înseamnă că dacă ați fi avut logică care să verifice `foo` în următoarea manieră: if ( foo === 1 ) { importantTask(); } // `importantTask()` nu s-ar evalua, chiar dacă `foo` are valoarea "1" // 3.B.1.2 // Se pot anticipa asftel de probleme prin folosirea operatorilor unari + sau -: foo = +document.getElementById("foo-input").value; // ^ operatorul unar + va converti operandul din dreapta într-un număr // typeof foo; // "number" if ( foo === 1 ) { importantTask(); } // `importantTask()` va fi apelat
Câteva cazuri comune, alături de constrângeri:
// 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 // De remarcat că cele de mai sus trebuie considerate "inteligente inutil" // E de preferat abordarea evidentă a comparării valorii returnate de // indexOf, după cum urmează: if ( array.indexOf( "a" ) >= 0 ) { // ... }
// 3.B.2.3 var num = 2.5; parseInt( num, 10 ); // e la fel ca... ~~num; num >> 0; num >>> 0; // Toate au ca rezultat 2 // De reținut totuși, numerele negative vor fi tratate diferit... var neg = -2.5; parseInt( neg, 10 ); // e la fel ca... ~~neg; neg >> 0; // Toate au ca rezultat -2 // Totuși... neg >>> 0; // Va avea ca rezultat 4294967294
-
// 4.1.1 // Când se evaluează dacă un array are dimensiune, // în loc de: if ( array.length > 0 ) ... // ...se evaluează valoarea de adevăr, după cum urmează: if ( array.length ) ... // 4.1.2 // Când se evaluează dacă un array este gol, // în loc de: if ( array.length === 0 ) ... // ...se evaluează valoarea de adevăr, după cum urmează: if ( !array.length ) ... // 4.1.3 // Când se evaluează dacă un string nu este gol, // în loc de: if ( string !== "" ) ... // ...se evaluează valoarea de adevăr, după cum urmează: if ( string ) ... // 4.1.4 // Când se evaluează dacă un string _este_ gol, // în loc de: if ( string === "" ) ... // ...se evaluează falsitatea, după cum urmează: if ( !string ) ... // 4.1.5 // Când se evaluează dacă o referință este adevarată, // în loc de: if ( foo === true ) ... // ...se evaluează așa cum are sens, profitând de capacitățile native ale limbajului: if ( foo ) ... // 4.1.6 // Când se evaluează dacă o referință este falsă, // în loc de: if ( foo === false ) ... // ...se folosește negarea pentru a constrânge o evaluare adevarată if ( !foo ) ... // ...Atenție, această declarație va funcționa și cu: 0, "", null, undefined, NaN // Dacă _TREBUIE_ verificată o valoare booleană falsă, se folosește if ( foo === false ) ... // 4.1.7 // Când se evaluează numai o referință care poate fi null sau undefined, dar NU și false, "" sau 0, // în loc de: if ( foo === null || foo === undefined ) ... // ...trebuie profitat de constrângerea tipului ==, după cum urmează: if ( foo == null ) ... // Reține, folosirea == va corespunde cu `null` atât pentru `null` cât și pentru `undefined` // dar nu și pentru `false`, "" sau 0 null == undefined
Se evaluează ÎNTOTDEAUNA pentru cel mai bun, cel mai precis rezultat - instrucțiunile de mai sus sunt o recomandare, nu o dogmă.
// 4.2.1 // Tipuri de constrângere și note de evaluare // Se preferă `===` în pofida `==` (cu excepția cazului care necesită evaluarea tipului declarat) // === nu constrânge tipul, ceea ce înseamnă că: "1" === 1; // false // == constrânge tipul, ceea ce înseamnă că: "1" == 1; // true // 4.2.2 // Valori Boolene, de Adevăr și Negative // Boolene: true, false // Valori de Adevăr: "foo", 1 // Valori Negative: "", 0, null, undefined, NaN, void 0
-
// 5.1.1 // Un modul practic (function( global ) { var Module = (function() { var data = "secret"; return { // Aceasta este o proprietate booleană bool: true, // O valoare string oarecare string: "a string", // O proprietare de tip array array: [ 1, 2, 3, 4 ], // O proprietate de tip obiect object: { lang: "en-Us" }, getData: function() { // returnează valoarea actuală a variabilei `data` return data; }, setData: function( value ) { // setează valoarea variabilei `data` și o returnează return ( data = value ); } }; })(); // Alte instrucțiuni pot urma aici // expune modulul obiectului global global.Module = Module; })( this );
// 5.2.1 // Un Constructor Practic (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 ); }; // Pentru a apela constructorul fără `new`, se poate utiliza: var ctor = function( foo ) { return new Ctor( foo ); }; // expune modulul obiectului global global.ctor = ctor; })( this );
-
A. Nu ești un compilator/compresor de cod uman, deci nu încerca să fii unul.
Următorul cod este un exemplu de nomenclatură greșită:
// 6.A.1.1 // Exemplu de cod cu denumire slabă function q(s) { return document.querySelectorAll(s); } var i,a=[],els=q("#foo"); for(i=0;i<els.length;i++){a.push(els[i]);}
Fără nicio îndoială, ai scris cod ca acesta - sperăm să se încheie azi.
Iată aceeași bucată de cod, dar cu o nomenclatură simpatică, mai expresivă (și o structură mai lizibilă):
// 6.A.2.1 // Exemplu de cod cu nomenclatură îmbunătățită 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 ] ); }
Câteva indicii suplimentare de nomenclatură:
// 6.A.3.1 // Nume de string-uri `dog` e un string // 6.A.3.2 // Nume de array-uri `dogs` e un array de string-uri `dog` // 6.A.3.3 // Nume de funcții, obiecte, instanțe, etc camelCase; funcții și declarații de variabile // 6.A.3.4 // Nume de constructori, prototipuri, etc. PascalCase; funcție constructor // 6.A.3.5 // Nume de expresii regulate rDesc = //; // 6.A.3.6 // Din ghidul de stil al librăriei Google Closure functionNamesLikeThis; variableNamesLikeThis; ConstructorNamesLikeThis; EnumNamesLikeThis; methodNamesLikeThis; SYMBOLIC_CONSTANTS_LIKE_THIS;
B. Variații ale
this
Dincolo de uzul general al metodelor
call
șiapply
, se preferă întotdeauna.bind( this )
sau o funcție echivalentă, pentru a crea definițiiBoundFunction
pentru invocarea ulterioară. Se recurge la aliasing când nu mai sunt alte opțiuni disponibile.// 6.B.1 function Device( opts ) { this.value = null; // deschide un stream asincron, // care va fi apelat continuu stream.read( opts.path, function( data ) { // Actualizează valoarea actuală a acestei instanțe // cu cea mai recentă valoare din // streamul de date this.value = data; }.bind(this) ); // Reglează frecvența evenimentelor emise de // această instanță Device setInterval(function() { // Emite un eveniment regulator this.emit("event"); }.bind(this), opts.freq || 100 ); } // Pretindem că am moștenit EventEmitter ;)
Când nu e disponibil, echivalente funcționale pentru
.bind
există în multe librării JavaScript moderne.// 6.B.2 // eg. 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 ); } // eg. 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 ); } // eg. 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 ); }
În ultimă instanță, creează un alias pentru
this
folosindself
drept Identifier. Această soluție este predispusă la bug-uri și trebuie evitată ori de câte ori este posibil.// 6.B.3 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. Folosește
thisArg
Mai multe metode prototype native din ES 5.1 vin cu semnătură
thisArg
specială, care ar trebui folosită ori de câte ori este posibil// 6.C.1 var obj; obj = { f: "foo", b: "bar", q: "qux" }; Object.keys( obj ).forEach(function( key ) { // |this| se referă acum la `obj` console.log( this[ key ] ); }, obj ); // <-- ultimul argument este `thisArg` // Afișează... // "foo" // "bar" // "qux"
thisArg
poate fi folosit împreună cuArray.prototype.every
,Array.prototype.forEach
,Array.prototype.some
,Array.prototype.map
,Array.prototype.filter
-
Această secțiune ilustrează idei și concepte care nu ar trebui considerate dogmatice, ci există pentru a încuraja practicile de punere sub semnul întrebării într-o încercare de a găsi căi mai bune pentru a executa sarcini comune în programarea JavaScript.
A. Utilizarea
switch
ar trebui evitată, metode moderne de tracing vor trece funcțiile cu declarații switch pe lista neagrăSe pare că există îmbunătățiri drastice ale executării declarațiilor
switch
în ultimele versiuni Firefox și Chrome. http://jsperf.com/switch-vs-object-literal-vs-moduleîmbunătățiri notabile pot fi observate și aici: #13
// 7.A.1.1 // Un exemplu de declarație switch switch( foo ) { case "alpha": alpha(); break; case "beta": beta(); break; default: // execută implicit break; } // 7.A.1.2 // O abordare mai bună ar fi folosirea un obiect literal sau chiar a unui modul: var switchObj = { alpha: function() { // declarații // return }, beta: function() { // declarații // return }, _default: function() { // declarații // return } }; var switchModule = (function () { return { alpha: function() { // declarații // return }, beta: function() { // declarații // return }, _default: function() { // declarații // return } }; })(); // 7.A.1.3 // Dacă `foo` este o proprietate a `switchObj` sau a `switchModule`, execută ca o metodă... ( Object.hasOwnProperty.call( switchObj, foo ) && switchObj[ foo ] || switchObj._default )( args ); ( Object.hasOwnProperty.call( switchObj, foo ) && switchModule[ foo ] || switchModule._default )( args ); // Dacă știți și aveți încredere în valoarea lui `foo`, ați putea chiar omite verificarea OR // păstrând doar execuția: switchObj[ foo ]( args ); switchModule[ foo ]( args ); // Acest șablon încurajează, de asemenea, reutilizarea codului.
B. "Return"-urile timpurii încurajează lizibilitatea codului cu diferențe de performanță neglijabile
// 7.B.1.1 // Incorect: function returnLate( foo ) { var ret; if ( foo ) { ret = "foo"; } else { ret = "quux"; } return ret; } // Corect: function returnEarly( foo ) { if ( foo ) { return "foo"; } return "quux"; }
-
Principiul de bază aici este:
Pentru a consolida acest concept, vizionați următoarea prezentare:
https://www.youtube.com/watch?v=xL3xCO7CLNM
- O singură linie deasupra codului la care se referă
- Comentariile pe mai multe linii sunt bune
- Comentariile la sfârșitul de linie sunt interzise!
- Stilul din JSDoc este bun, dar necesită o investiție substanțială de timp
-
Programele ar trebui scrise într-un singur limbaj, oricare ar fi el, așa cum a fost dictat de administrator sau administratori.
Orice proiect care are ca referință acest document la baza ghidului de stilizare nu va accepta o formatare de tip prima virgulă (comma first), cu excepția cazului în care acest lucru a fost specificat diferit de autorul proiectului.