Questo è un documento in continua evoluzione e nuove idee sono sempre bene accette. Per contribuire: 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
- Firede @firede github
- monkadd github
- Stephan Lindauer @stephanlindauer, github
- Thomas P @dragon5689 github
- Yotam Ofek @yotamofek github
- Duc Nguyen @ducntq, github
- James Young @jamsyoung, github
- Stephane Moreau github
- Boris Nekezov github
- Akshat Joshi @akshat_joshi, github
Tutto il codice, in qualsiasi linguaggio sia, dovrebbe sembrare come scritto da un'unica persona, non importa quante persone vi abbiano contribuito.
Il seguente elenco, evidenzia le pratiche che utilizzo in tutto il codice di cui sono l'autore originale; contributi ai progetti da me creati dovrebbero seguire queste linee guida.
Non è mia intenzione imporre il mio stile su codice o progetti altrui; se esiste già uno stile comune, esso dovrebbe essere rispettato.
"Discussioni sullo stile sono inutili. Ci dovrebbe essere una guida di stile, e voi dovreste seguirla"
Rebecca Murphey
"Parte dell'essere un buon amministratore in un progetto votato al successo è capire che la scrittura di codice per sé stessi è una Cattiva Idea™. Se migliaia di persone usano il tuo codice, allora scrivi il tuo codice in modo che abbia la massima chiarezza, e non seguendo i tuoi gusti personali su come renderlo chiaro all'interno delle specifiche."
Idan Gazit
- ORIGINAL
- Bulgarian
- German
- French
- Spanish
- Portuguese - Brazil
- Korean
- Japanese
- Italian
- Russian
- Romanian
- 简体中文
- Serbian - cyrilic alphabet
- Serbian - latin aplphabet
- Greek
- Hindi
- JavaScript Plugin per Sonar
- Plato
- jsPerf
- jsFiddle
- jsbin
- JavaScript Lint (JSL)
- jshint
- jslint
- jscs
- Editorconfig
I seguenti dovrebbero essere considerati come 1) incompleti e 2) LETTURE NECESSARIE. Non sempre sono d'accordo con lo stile scritto dagli autori qui sotto, ma una cosa è certa: sono consistenti. Quindi, sono da considerare delle autorità per questo linguaggio.
- Baseline For Front End Developers
- Eloquent JavaScript
- JavaScript, JavaScript
- Adventures in JavaScript Development
- Perfection Kills
- Douglas Crockford's Wrrrld Wide Web
- JS Assessment
Ogni progetto dovrebbe sempre cercare di fornire un qualche strumento generico, per mezzo del quale i sorgenti possano venire validati, testati e compressi per il successivo utilizzo in ambiente di produzione. Per questo lavoro, grunt di Ben Alman non è secondo a nessuno e ha ufficialmente rimpiazzato la directory "kits/" di questo repo.
I progetti devono includere una qualche sorta di unità, guida o implementazione di test oppure un test funzionale. Dimostrazioni di casi d'uso NON SONO QUALIFICATI come "test". La seguente è una lista di framework per il testing, nessuno dei quali è preferito rispetto all'altro.
- Spazio vuoto
- Bella sintassi
- Controllo dei tipi (offerto dalle linee guida della jQuery Core Style)
- Esecuzione condizionale
- Stile pratico
- Nomenclatura
- Varie
- Oggetti nativi e ospite
- Commenti
- Un codice di linguaggio
Le seguenti sezioni evidenziano una ragionevole guida di stile per il moderno sviluppo di JavaScript, e non sono intese per essere obbligatorie. Il concetto più importante è la legge sulla consistenza dello stile nel codice. Qualsiasi stile scegliate per i vostri progetti dovrebbe essere considerato legge. Potete mettere un link a questo documento come espressione di impegno alla consistenza, leggibilità e manutenibilità del codice del vostro progetto.
- Mai mischiare spazi e tabulazioni.
- Quando iniziate un progetto, prima di cominciare a scrivere il codice, scegliete tra indentazione soft (spazi) o tabulazioni reali, e considerate questa scelta legge.
- Per la leggibilità, raccomando sempre di impostare la dimensione dei rientri del proprio editor a due caratteri — questo significa, due spazi o due spazi rappresentanti una tabulazione reale.
- Se il vostro editor lo supporta, lavorate sempre con l'impostazione "mostra caratteri invisibili" attiva. I benefici di questa pratica sono:
- Rafforzata consistenza
- Eliminazione di spazi vuoti alla fine delle linee
- Eliminazione di linee vuote
- Commit e diff più facili da leggere
- Usate Editorconfig quando possibile. Supporta la maggior parte degli IDE e gestisce la maggior parte delle impostazioni per gli spazi vuoti.
-
A. Parentesi, parentesi graffe, interruzioni di linea
// if/else/for/while/try hanno sempre spazi, parentesi graffe e sono suddivisi su // più linee, questo incoragga la leggibilità // 2.A.1.1 // Esempi di sintassi veramente illeggibile if(condition) doSomething(); while(condition) iterating++; for(var i=0;i<100;i++) someIterativeFn(); // 2.A.1.1 // Uso degli spazi vuoti per incrementare la leggibilità if ( condizione ) { // istruzioni } while ( condizione ) { // istruzioni } for ( var i = 0; i < 100; i++ ) { // istruzioni } // Ancora meglio: var i, length = 100; for ( i = 0; i < length; i++ ) { // istruzioni } // Oppure... var i = 0, length = 100; for ( ; i < length; i++ ) { // istruzioni } var prop; for ( prop in object ) { // istruzioni } if ( true ) { // istruzioni } else { // istruzioni }
B. Assegnazioni, dichiarazioni, funzioni ( non anonima, espressione, costruttore )
// 2.B.1.1 // Variabili var foo = "bar", num = 1, undef; // Notazioni literal: var array = [], object = {}; // 2.B.1.2 // L'utilizzo di una sola `var` per scope (funzione) incrementa la leggibilità // e mantiene la tua lista di dichiarazioni ordinata (inoltre riduce il numero di digitazioni) // Sbagliato var foo = ""; var bar = ""; var qux; // Corretto var foo = "", bar = "", quux; // oppure... var // Commento su questa linea foo = "", bar = "", quux; // 2.B.1.3 // le dichiarazioni var dovrebbero sempre risiedere all'inizio del rispettivo scope (funzione). // Lo stesso vale per const e let di ECMAScript 6. // Sbagliato function foo() { // alcune istruzioni qui var bar = "", qux; } // Corretto function foo() { var bar = "", qux; // tutto il codice dopo le dichiarazioni delle variabili. } // 2.B.1.4 // const e let, da ECMAScript 6, dovrebbero essere posizionate all'inizio del loro scope (blocco). // Sbagliato function foo() { let foo, bar; if ( condition ) { bar = ""; // istruzioni } } // Corretto function foo() { let foo; if ( condition ) { let bar = ""; // istruzioni } }
// 2.B.2.1 // Dichiarazione di funzione non anonima function foo( arg1, argN ) { } // Utilizzo foo( arg1, argN ); // 2.B.2.2 // Dichiarazione di funzione non anonima function square( number ) { return number * number; } // Utilizzo square( 10 ); // Stile forzato di passaggio dei parametri a cascata function square( number, callback ) { callback( number * number ); } square( 10, function( square ) { // istruzioni di callback }); // 2.B.2.3 // Funzione espressione var square = function( number ) { // Ritorna qualcosa di importante e rilevante return number * number; }; // Funzione espressione con identificatore // Questa è la variante preferita, ha il valore aggiunto di essere in grado // di richiamare sé stessa ed ha un'identità nelle tracce dello stack: var factorial = function factorial( number ) { if ( number < 2 ) { return 1; } return number * factorial( number - 1 ); }; // 2.B.2.4 // Dichiarazione di costruttore function FooBar( options ) { this.options = options; } // Utilizzo var fooBar = new FooBar({ a: "alpha" }); fooBar.options; // { a: "alpha" }
C. Eccezioni, lievi deviazioni
// 2.C.1.1 // Funzioni con callback foo(function() { // Nota che non ci sono spazi tra la prima parentesi // della funzione chiamata in esecuzione e la parola "function" }); // Funzione che accetta un array, nessuno spazio foo([ "alpha", "beta" ]); // 2.C.1.2 // Funzione che accetta un oggetto, nessuno spazio foo({ a: "alpha", b: "beta" }); // Singolo argomento stringa, nessuno spazio foo("bar"); // Parentesi interne di raggruppamento, nessuno spazio if ( !("foo" in obj) ) { }
D. La consistenza vince sempre
Nelle sezioni da 2.A a 2.C, le regole per lo spazio vuoto vengono stabilite come raccomandazione per un motivo semplice ed importante: la consistenza. È importante notare che le preferenze di formattazione, come lo "spazio vuoto interno" dovrebbero essere considerate opzionali, ma solo uno stile dovrebbe esistere per l'intero sorgente del vostro progetto.
// 2.D.1.1 if (condizione) { // istruzioni } while (condizione) { // istruzioni } for (var i = 0; i < 100; i++) { // istruzioni } if (true) { // istruzioni } else { // istruzioni }
E. Apici
Che preferiate singoli o doppi apici non importa, non c'è differenza di gestione da parte di JavaScript. Ciò che DEVE ASSOLUTAMENTE essere mantenuta è la consistenza. Mai mischiare gli apici nello stesso progetto. Scegliete uno stile e proseguite con esso.
F. Fine delle linee e linee vuote
Lo spazio vuoto può complicare le diff e rendere le modifiche impossibili da leggere. Considerate di implementare un hook di pre-commit che rimuova automaticamente lo spazio vuoto alla fine delle linee e gli spazi vuoti nelle linee vuote.
-
Controllo di tipo (offerto dalle linee guida della jQuery Core Style)
A. Tipi attuali
Stringa:
typeof variable === "string"
Numero:
typeof variable === "number"
Booleano:
typeof variable === "boolean"
Oggetto:
typeof variable === "object"
Array:
Array.isArray( arrayLikeObject ) (dove possibile)
Nodo:
elem.nodeType === 1
Nullo:
variable === null
Nullo o non definito (undefined):
variable == null
Non definito:
Variabili globali:
typeof variable === "undefined"
Variabili locali:
variable === undefined
Proprietà:
object.prop === undefined object.hasOwnProperty( prop ) "prop" in object
B. Tipi forzati
Considerate le implicazioni di ciò che segue...
Dato questo codice HTML:
<input type="text" id="foo-input" value="1">
// 3.B.1.1 // `foo` è stato dichiarato di valore `0` ed il suo tipo è `number` var foo = 0; // typeof foo; // "number" ... // Successivamente, in qualche altra parte del codice, necessitate di aggiornare `foo` // con un nuovo valore derivato da un elemento input foo = document.getElementById("foo-input").value; // Se testaste `typeof foo` adesso, il risultato sarebbe `string` // Ciò significa che se aveste del codice che testa `foo` in questo modo: if ( foo === 1 ) { importantTask(); } // `importantTask()` non verrebbe mai eseguito, anche se `foo` fosse di valore "1" // 3.B.1.2 // Potete prevenire questi problemi usando la forzatura intelligente con gli operatori unari + o -: foo = +document.getElementById("foo-input").value; // ^ l'operatore + unario convertirà il suo operando destro in un numero // typeof foo; // "number" if ( foo === 1 ) { importantTask(); } // `importantTask()` verrà eseguito
Ecco alcuni casi comuni con forzature:
// 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 // Tenete presente che i summenzionati esempi dovrebbero essere considerati come "eccessivamente chiari" // È da preferire il più ovvio approccio di comparazione del valore ritornato // da indexOf, cioè: if ( array.indexOf( "a" ) >= 0 ) { // ... }
// 3.B.2.4 var num = 2.5; parseInt( num, 10 ); // è l'equivalente di... ~~num; num >> 0; num >>> 0; // Tutti danno come risultato 2 // Comunque ricordate che i numeri negativi verranno trattati differentemente... var neg = -2.5; parseInt( neg, 10 ); // è l'equivalente di... ~~neg; neg >> 0; // Tutti danno come risultato -2 // Ma... neg >>> 0 // Darà come risultato 4294967294
-
// 4.1.1 // Quando si deve solo stabilire se un array ha una dimensione, // invece di questo: if ( array.length > 0 ) ... // ...verificate la verità condizionale, in questo modo: if ( array.length ) ... // 4.1.2 // Quando si deve solo stabilire che un array è vuoto, // invece di questo: if ( array.length === 0 ) ... // ...verificate la verità condizionale, in questo modo: if ( !array.length ) ... // 4.1.3 // Quando si deve solo stabilire che una stringa non è vuota, // invece di questo: if ( string !== "" ) ... // ...verificate la verità condizionale, in questo modo: if ( string ) ... // 4.1.4 // Quando si deve solo stabilire che una stringa _è_ vuota, // invece di questo: if ( string === "" ) ... // ...verificate la verità condizionale, in questo modo: if ( !string ) ... // 4.1.5 // Quando si deve solo stabilire che un riferimento è vero, // invece di questo: if ( foo === true ) ... // ...verificatelo per il suo significato, avvantaggiatevi delle funzionalità proprie del linguaggio: if ( foo ) ... // 4.1.6 // Quando si deve solo stabilire che un riferimento è falso, // invece di questo: if ( foo === false ) ... // ...usate la negazione per forzare una valutazione vera if ( !foo ) ... // ...ma state attenti, questo varrà anche per: 0, "", null, undefined, NaN // Se _DOVETE_ testare per un falso booleano, allora usate if ( foo === false ) ... // 4.1.7 // Quando si deve solo stabilire che un riferimento potrebbe essere null o undefined, // ma NON falso, "" o 0, invece di questo: if ( foo === null || foo === undefined ) ... // ...avvantaggiatevi della forzatura di tipo fatta da ==, in questo modo: if ( foo == null ) ... // Ricordate, l'uso di == farà corrispondere un `null` SIA a `null` che a `undefined` // ma non a `false`, "" o 0 null == undefined
Valutate SEMPRE per il risultato migliore e più accurato - quella sopra è una linea guida, non un dogma.
// 4.2.1 // Note sulla forzatura di tipo e sulla valutazione // Preferite `===` a `==` (a meno che il caso non richieda una valutazione di tipo meno restrittiva) // === non forza il tipo, ciò significa che: "1" === 1: // false // == forza il tipo, ciò significa che: "1" == 1; // true // 4.2.2 // Booleani, verità e falsità // Booleani: true, false // Verità: "foo", 1 // Falsità: "", 0, null, undefined, NaN, void 0
-
// 5.1.1 // Un modulo pratico (function( global ) { var Module = (function() { var data = "secret"; return { // Proprietà booleana bool: true, // Un valore stringa string: "a string", // Una proprietà array array: [ 1, 2, 3, 4 ], // Una proprietà oggetto object: { lang: "en-US" }, getData: function() { // ottiene il valore corrente di `data` return data; }, setData: function( value ) { // imposta il valore di `data` e lo ritorna return ( data = value ); } }; })(); // Altre istruzioni // esponiamo il nostro modulo all'oggetto globale global.Module = Module; })( this );
// 5.2.1 // Un costruttore pratico (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 ); }; // Per richiamare il costruttore senza `new`, potreste fare così: var ctor = function( foo ) { return new Ctor( foo ); }; // esponiamo il nostro costruttore all'oggetto globale global.ctor = ctor; })( this );
-
A. Non siete un compilatore/compressore umano di codice, quindi non cercate di esserlo.
Il seguente codice è un esempio di tremenda nomenclatura:
// 6.A.1.1 // Esempio di codice con nomi per nulla chiari function q(s) { return document.querySelectorAll(s); } var i,a=[],els=q("#foo"); for(i=0;i<els.length;i++){a.push(els[i]);}
Sicuramente avrete scritto codice come questo - con la speranza che ciò finisca oggi.
Ecco lo stesso pezzo di codice, ma con una nomencaltura più riflessiva ed esplicativa (ed una struttura leggibile):
// 6.A.2.1 // Esempio di codice con nomi migliorati 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 ] ); }
Alcune ulteriori considerazioni:
// 6.A.3.1 // Nominare stringhe `dog` è una stringa // 6.A.3.2 // Nominare array `dogs` è un array di stringhe `dog` // 6.A.3.3 // Nominare funzioni, oggetti, istanze, ecc. camelCase; dichiarazioni di funzione e variabile // 6.A.3.4 // Nominare costruttori, prototipi, ecc. PascalCase; funzione costruttore // 6.A.3.5 // Nominare espressioni regolari rDesc = //; // 6.A.3.6 // Dalla guida allo stile della libreria di Google Closure functionNamesLikeThis; variableNamesLikeThis; ConstructorNamesLikeThis; EnumNamesLikeThis; methodNamesLikeThis; SYMBOLIC_CONSTANTS_LIKE_THIS;
B. La varie faccie di
this
Oltre ai generalmente ben conosciuti casi d'uso di
call
eapply
, preferite sempre.bind( this )
o una funzione equivalente, per la creazione di definizioniBoundFunction
che dovranno successivamente essere invocate. Ricorrete all'aliasing solo quando non ci sono altre opzioni disponibili.// 6.B.1 function Device( opts ) { this.value = null; // apre uno flusso asincrono, // questo verrà richiamato continuamente stream.read( opts.path, function( data ) { // Aggiorna il valore corrente di questa istanza // con il più recente valore recuperato dal // flusso di dati this.value = data; }.bind(this) ); // Regola la frequenza degli eventi emessi da // questa istanza di Device setInterval(function() { // Emette un evento regolato this.emit("event"); }.bind(this), opts.freq || 100 ); } // Fate finta che abbiamo ereditato EventEmitter ;)
Quando non disponibile, funzioni equivalenti a
.bind
esistono in molte librerie JavaScript moderne.// 6.B.2 // es. 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 ); } // es. 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 ); } // es. 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 ); }
Come ultima risorsa, create un alias a
this
usandoself
come identificatore. Con questo approccio è estremamente facile generare bug e dovrebbe essere evitato ogni volta che è possibile.// 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. Uso di
thisArg
Diversi metodi di istanza delle funzioni interni di ES 5.1 forniscono una speciale firma
thisArg
, che dovrebbe essere usata tutte le volte che è possibile// 6.C.1 var obj; obj = { f: "foo", b: "bar", q: "qux" }; Object.keys( obj ).forEach(function( key ) { // |this| ora fa riferimento a `obj` console.log( this[ key ] ); }, obj ); // <-- l'ultimo argomento è `thisArg` // Stampa... // "foo" // "bar" // "qux"
thisArg
può essere usato conArray.prototype.every
,Array.prototype.forEach
,Array.prototype.some
,Array.prototype.map
,Array.prototype.filter
-
Questa sezione servirà ad illustrare idee e concetti che non dovrebbero essere considerati un dogma, ma che invece esistono per incoraggiare pratiche di analisi nel tentativo di ricercare le migliori modalità per eseguire attività comuni di programmazione JavaScript.
A. L'utilizzo di
switch
dovrebbe essere evitato, il metodo moderno di analisi metterà nella lista nera le funzioni con istruzioni switchSembra che ci siano drastici miglioramenti nell'esecuzione di istruzioni
switch
nelle ultime release di Firefox e Chrome. http://jsperf.com/switch-vs-object-literal-vs-moduleVisibili miglioramenti vengono riportati anche qui: #13
// 7.A.1.1 // Un esempio di istruzione switch switch( foo ) { case "alpha": alpha(); break; case "beta": beta(); break; default: // qualcosa da eseguire di default break; } // 7.A.1.2 // Un approccio alternativo che supporta componibilità e riusabilità è di // usare un oggetto come magazzino dei "casi" ed una funzione per delegare: var cases, delegator; // I return sono solo a titolo esplicativo. cases = { alpha: function() { // istruzioni // un return return [ "Alpha", arguments.length ]; }, beta: function() { // istruzioni // un return return [ "Beta", arguments.length ]; }, _default: function() { // istruzioni // un return return [ "Default", arguments.length ] } }; delegator = function() { var args, key, delegate; // Trasforma la lista degli argomenti in un array args = [].slice.call( arguments ); // Estrae la chiave del caso dagli argomenti key = args.shift(); // Assegna il gestore del caso di default delegate = cases._default; // Risale al metodo al quale delegare l'esecuzione if ( cases.hasOwnProperties( key ) ) { delegate = cases[ key ]; } // L'argomento dello scope può essere impostato a qualcosa di specifico, // in questo caso, |null| sarà sufficiente return delegate.apply( null, args ); }; // 7.A.1.3 // Per funzionare prendiamo la API di 7.A.1.2: delegator( "alpha", 1, 2, 3, 4, 5 ); // [ "Alpha", 5 ] // Ovviamente, l'argomento chiave `case` può facilmente essere basato // su qualche altra condizione arbitraria. var caseKey, someUserInput; // Qualche possibile tipo di input da un form? someUserInput = 9; if ( someUserInput > 10 ) { caseKey = "alpha"; } else { caseKey = "beta"; } // oppure... caseKey = someUserInput > 10 ? "alpha" : "beta"; // E quindi... delegator( caseKey, someUserInput ); // [ "Beta", 1 ] // E ovviamente... delegator(); // [ "Default", 0 ]
B. I ritorni da funzione anticipati promuovono la leggibilità del codice a fronte di una differenza di performance trascurabile
// 7.B.1.1 // Sbagliato: function returnLate( foo ) { var ret; if ( foo ) { ret = "foo"; } else { ret = "quux"; } return ret; } // Corretto: function returnEarly( foo ) { if ( foo ) { return "foo"; } return "quux"; }
-
Il principio base qui è:
Per rafforzare questo concetto, date un'occhiata alla seguente presentazione:
-
I programmi dovrebbero essere scritti in un linguaggio, qualsiasi esso sia, come richiesto dal mantenitore o dai mantenitori.
Qualsiasi progetto che citi questo documento come sua guida base di stile non accetterà la formattazione comma first del codice, a meno che non sia esplicitamente specificato dall'autore del progetto.
Principles of Writing Consistent, Idiomatic JavaScript by Rick Waldron and Contributors is licensed under a Creative Commons Attribution 3.0 Unported License.
Based on a work at github.com/rwldrn/idiomatic.js.