Introduction
Image from Pluralsight
Good code is not just functional, but also elegant. Elegant code must be:
Consistent in its style
In a series of posts, we'll discuss coding style for the JavaScriptlanguage. In this second post, we'll focus on style guidelines for whitespace.
Summary
The style guidelines for JavaScript whitespace are broken down into the following categories:
Indentation
Spaces Around
Spaces Before
Spaces After
Spaces Not Allowed
Blank Lines
Other
Each category is is explained below. Must you follow these guidelines? No. Should you? Yes.
Indentation
The indentation guidelines for JavaScript are:
Require indentation with four (4) spaces
Disallow tabs for indentation
For example, this is good:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | function Log() { var now, // current date/time elapsed, // elapsed milliseconds since we initialized the stats messagesPerSec, // number of messages/sec since initialization charsPerSec, // number of message character/sec since initialization idList, // the comma-delimited list of ids prop; // an object property now = Now(); elapsed = now - this.start; messagesPerSec = ( this.messages / ( elapsed / 1000 ) ); charsPerSec = ( this.chars / ( elapsed / 1000 ) ); for ( prop in this.ids ) { if ( this.ids.hasOwnProperty( prop ) ) { if ( !idList ) { idList = prop; } else { idList = idList + "," + prop; } } } options.log( "SOCKET(" + idList + "): Stats - " + messagesPerSec.toFixed( 1 ) + " msg/sec, " + charsPerSec.toFixed( 0 ) + " char/sec" ); } |
and this is bad:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | function Log() { var now, // current date/time elapsed, // elapsed milliseconds since we initialized the stats messagesPerSec, // number of messages/sec since initialization charsPerSec, // number of message character/sec since initialization idList, // the comma-delimited list of ids prop; // an object property now = Now(); elapsed = now - this.start; messagesPerSec = ( this.messages / ( elapsed / 1000 ) ); charsPerSec = ( this.chars / ( elapsed / 1000 ) ); for ( prop in this.ids ) { if ( this.ids.hasOwnProperty( prop ) ) { if ( !idList ) { idList = prop; // BAD: indentation uses two (2) spaces } else { // BAD: indentation uses tabs (trust me on this one) idList = idList + "," + prop; } } } options.log( "SOCKET(" + idList + "): Stats - " + messagesPerSec.toFixed( 1 ) + " msg/sec, " + charsPerSec.toFixed( 0 ) + " char/sec" ); } |
Spaces Around
Spaces are required around:
The content of square brackets - []
The content of parentheses - ()
The content of curly braces - {}
For example, this is good:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | function getDaysInMonth( month, year ) { var monthDays, days; monthDays = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ]; if ( month === 2 ) { // february, taking leap years into account if ( year % 400 === 0 ) { days = 29; } else if ( ( year % 4 === 0 ) && ( year % 100 !== 0 ) ) { days = 29; } else { days = 28; } } else { // all other months days = monthDays[ month - 1 ]; } return { "days": days }; } |
and this is bad:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | function getDaysInMonth(month, year) { var monthDays, days; monthDays=[31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; if (month===2) { // BAD: no spaces around () content // february, taking leap years into account if (year%400===0) { days=29; } else if ((year%4===0)&&(year%100!==0)) { days=29; } else { days=28; // BAD: no spaces around infix operator } } else { // all other months days=monthDays[month-1]; // BAD: no spaces around [] content } return {"days": days}; // BAD: no spaces around {} content } |
Spaces Before
Spaces are required before:
Blocks
Keywords (break, catch, class, const, continue, do, else, finally, for, function, if, let, return, switch, throw, try, var, while, with, yield)
Object literal property values
For example, this is good:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | function getDaysInMonth( month, year ) { var monthDays, days; monthDays = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ]; if ( month === 2 ) { // february, taking leap years into account if ( year % 400 === 0 ) { days = 29; } else if ( ( year % 4 === 0 ) && ( year % 100 !== 0 ) ) { days = 29; } else { days = 28; } } else { // all other months days = monthDays[ month - 1 ]; } return { "days": days }; } |
and this is bad:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | function getDaysInMonth( month, year ){ var monthDays, days; monthDays = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ]; if ( month === 2 ){ // BAD: no space before block // february, taking leap years into account if ( year % 400 === 0 ){ days = 29; }else if ( ( year % 4 === 0 ) && ( year % 100 !== 0 ) ){ days = 29; }else{ days = 28; } }else{ // BAD: no space before "else" keyword // all other months days = monthDays[ month - 1 ]; } return{ "days":days }; // BAD: no space before object literal property value } |
Spaces After
Spaces are required after:
Commas
Semicolons
Keywords (case, catch, do, else, finally, for, if, return, switch, throw, try, while, with)
Unary word operators (delete, new, typeof, void, yield)
Start of comments
For example, this is good:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | function ApplyConfigToWidgets() { var config, ids, i; config = gConfig; ids = []; if ( config && config.widgets ) { // load proper content into each widget, via ajax for ( i = 0; i < config.widgets.length; i++ ) { // define a closure to isolate state instance ( function( state ) { var method, code, config, $placeholder, start, stop; if ( "swatWidgetType" in state ) { // extract information from state code = state.swatWidgetType.replace( /^sw-/, "" ); method = state.swatWidgetType.replace( /^sw-dashboard/, "" ); config = state.swatConfig; // locate placeholder $placeholder = $( "#" + ids[ i ] ); // load widget content via ajax LoadWidgetViaAjax( { "$container": $placeholder, "code": code, "method": method, "config": config } ); } } )( config.widgets[ i ] ); } } } |
and this is bad:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | function ApplyConfigToWidgets() { var config,ids,i; // BAD: no space after commas config = gConfig; ids = []; if( config && config.widgets ) { //load proper content into each widget, via ajax for( i = 0;i < config.widgets.length;i++ ) { // BAD: no space after semicolons //define a closure to isolate state instance ( function( state ) { var method,code,config,$placeholder,start,stop; if( "swatWidgetType" in state ) { // BAD: no space after keyword //extract information from state code = state.swatWidgetType.replace( /^sw-/,"" ); method = state.swatWidgetType.replace( /^sw-dashboard/,"" ); config = state.swatConfig; //locate placeholder // BAD: no space after start of comment $placeholder = $( "#" + ids[ i ] ); //load widget content via ajax LoadWidgetViaAjax( { "$container": $placeholder, "code": code, "method": method, "config": config } ); } } )( config.widgets[ i ] ); } } } |
Spaces Not Allowed
Spaces are not allowed:
Before commas
Before semicolons
Before another space (i.e. multiple spaces)
Before the opening parenthesis of a function (definition or call)
After unary non-word operators (-, +, --, ++, !, !!)
For example, this is good:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | function ApplyConfigToWidgets() { var config, ids, i; config = gConfig; ids = []; if ( config && config.widgets ) { // load proper content into each widget, via ajax for ( i = 0; i < config.widgets.length; ++i ) { // define a closure to isolate state instance ( function( state ) { var method, code, config, $placeholder, start, stop; if ( "swatWidgetType" in state ) { // extract information from state code = state.swatWidgetType.replace( /^sw-/, "" ); method = state.swatWidgetType.replace( /^sw-dashboard/, "" ); config = state.swatConfig; // locate placeholder $placeholder = $( "#" + ids[ i ] ); // load widget content via ajax LoadWidgetViaAjax( { "$container": $placeholder, "code": code, "method": method, "config": config } ); } } )( config.widgets[ i ] ); } } } |
and this is bad:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | function ApplyConfigToWidgets () { var config , // BAD: space before comma ids , i ; // BAD: space before semicolon config = gConfig ; ids = [] ; // BAD: space before space (multiple spaces) if ( config && config.widgets ) { // load proper content into each widget , via ajax for ( i = 0 ; i < config.widgets.length ; ++ i ) { // BAD: space after unary non-word operator (++) // define a closure to isolate state instance ( function ( state ) { // BAD: space before function ()s var method , code , config , $placeholder , start , stop ; if ( "swatWidgetType" in state ) { // extract information from state code = state.swatWidgetType.replace ( /^sw-/ , "" ) ; method = state.swatWidgetType.replace ( /^sw-dashboard/ , "" ) ; config = state.swatConfig ; // locate placeholder $placeholder = $( "#" + ids[ i ] ) ; // load widget content via ajax LoadWidgetViaAjax ( { "$container": $placeholder , "code": code , "method": method , "config": config } ) ; } } ) ( config.widgets[ i ] ) ; } } } |
Blank Lines
Blank lines are required:
After a `var` statement
Before a comment
At the end of the file
Blank lines are not allowed:
After a comment
After a blank line (e.g. multiple blank lines)
For example, this is good:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | function getDaysInMonth( month, year ) { var monthDays, days; monthDays = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ]; if ( month === 2 ) { // february, taking leap years into account if ( year % 400 === 0 ) { days = 29; } else if ( ( year % 4 === 0 ) && ( year % 100 !== 0 ) ) { days = 29; } else { days = 28; } } else { // all other months days = monthDays[ month - 1 ]; } return { "days": days }; } |
and this is bad:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | function getDaysInMonth( month, year ) { var monthDays, days; // BAD: missing blank line after `var` statement monthDays = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ]; if ( month === 2 ) { // february, taking leap years into account // BAD: missing blank line before comment // BAD: blank line after comment if ( year % 400 === 0 ) { days = 29; } else if ( ( year % 4 === 0 ) && ( year % 100 !== 0 ) ) { days = 29; } else { days = 28; } } else { // all other months days = monthDays[ month - 1 ]; } // BAD: multiple blank lines return { "days": days }; } // BAD: missing blank line at end of file |
Other
Other whitespace guidelines for JavaScript are:
Use consistent line breaks
Avoid irregular whitespace characters (e.g. zero width space, non-breaking space, vertical tab, etc.)
By definition, line breaks and irregular whitespace characters are invisible, so we can't provide a meaningful visual example here.
Next time
Function conventions.