Image from Pluralsight
Introduction
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 JavaScript language. In this first post, we'll focus on style guidelines for variables.
Summary
The style guidelines for JavaScript variables are:
Declare all variables at the top of the function
Use a single var statement
Document the meaning of each variable
Separate variable initialization from variable declaration
Use CamelCase starting with a lowercase letter
"Apps Hungarian" notation is acceptable; "System Hungarian" is not
Each guideline is explained below. Must you follow these guidelines? No. Should you? Yes.
Declare all variables at the top of the function
In JavaScript, all variables have function scope, not block scope. We declare all variables at the top of the function to make this explicit and avoid misleading the reader with a variable that looks like it has block scope.
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 | /** * Is the connection silent? If we haven't received any messages in the silence interval, * then we are. * * @return {boolean} Is the connection silent? */ function Silent() { var now, // current date/time (GOOD) silent; // is the connection silent? now = new Date(); silent = false; if ( myLastWebSocketMessageDate ) { if ( now - myLastWebSocketMessageDate > options.intervals.silence ) { silent = true; } } return silent; } |
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 | /** * Is the connection silent? If we haven't received any messages in the silence interval, * then we are. * * @return {boolean} Is the connection silent? */ function Silent() { var silent; // is the connection silent? silent = false; if ( myLastWebSocketMessageDate ) { var now = new Date(); // BAD if ( now - myLastWebSocketMessageDate > options.intervals.silence ) { silent = true; } } return silent; } |
Learn more about variable scope.
Use a single var statement
Use a single var statement for all variables in a function. Do not use one var statement per variable.
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 | /** * Is the connection silent? If we haven't received any messages in the silence interval, * then we are. * * @return {boolean} Is the connection silent? */ function Silent() { var now, // current date/time (GOOD) silent; // is the connection silent? now = new Date(); silent = false; if ( myLastWebSocketMessageDate ) { if ( now - myLastWebSocketMessageDate > options.intervals.silence ) { silent = true; } } return silent; } |
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 | /** * Is the connection silent? If we haven't received any messages in the silence interval, * then we are. * * @return {boolean} Is the connection silent? */ function Silent() { var now; // current date/time var silent; // is the connection silent? (BAD) now = new Date(); silent = false; if ( myLastWebSocketMessageDate ) { if ( now - myLastWebSocketMessageDate > options.intervals.silence ) { silent = true; } } return silent; } |
Learn more about why a single var statement is good.
Document the meaning of each variable
Unless the meaning of a given variable is intuitively clear (e.g. headerHeight for the height of a header), then use an inline comment to document the meaning of the variable.
For example, this is good:
1 2 3 4 5 6 7 8 9 10 11 12 | function GenerateUpdateEventsForMetrics( a ) { var i, // the array index metric, // one metric in the array (GOOD) events, // an object representing an associative array of events zones; // the codes for the warning and danger zones events = {}; zones = [ "", "warning", "danger" ]; // code omitted for clarity } |
and this is bad:
1 2 3 4 5 6 7 8 9 10 11 12 | function GenerateUpdateEventsForMetrics( a ) { var i, metric, // BAD events, zones; events = {}; zones = [ "", "warning", "danger" ]; // code omitted for clarity } |
Separate variable initialization from variable declaration
Do not initialize a variable inside the variable declaration. By separating the declaration and the initialization, we provide additional clarity to the code. Also, this provides us the opportunity (if needed) to provide separate comments for both the meaning of the variable (in the declaration) and the default value for the variable (in the initialization).
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 Position() { var widgetHeight, headerHeight, footerHeight, containerHeight; widgetHeight = self.context.$widget.innerHeight(); // GOOD headerHeight = self.context.$header.innerHeight(); footerHeight = self.context.$footer.innerHeight(); containerHeight = widgetHeight - headerHeight - footerHeight; // if overlaying the footer, don't subtract out its height if ( options.overlayFooter ) { containerHeight += footerHeight; } // set the height of the content to fill the vertical space self.context.$container.innerHeight( containerHeight ); // if overlaying the footer, set a negative margin on the footer equal to its height, // to pull it back into view if ( options.overlayFooter ) { self.context.$footer.css( "margin-top", -1 * footerHeight ); } } |
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 | function Position() { var widgetHeight = self.context.$widget.innerHeight(), // BAD headerHeight = self.context.$header.innerHeight(), footerHeight = self.context.$footer.innerHeight(), containerHeight = widgetHeight - headerHeight - footerHeight; // if overlaying the footer, don't subtract out its height if ( options.overlayFooter ) { containerHeight += footerHeight; } // set the height of the content to fill the vertical space self.context.$container.innerHeight( containerHeight ); // if overlaying the footer, set a negative margin on the footer equal to its height, // to pull it back into view if ( options.overlayFooter ) { self.context.$footer.css( "margin-top", -1 * footerHeight ); } } |
Use CamelCase starting with a lowercase letter
When naming a variable, use CamelCase starting with a lowercase letter. Do not use underscores to separate words in a compound name.
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 Position() { var widgetHeight, // GOOD headerHeight, footerHeight, containerHeight; widgetHeight = self.context.$widget.innerHeight(); headerHeight = self.context.$header.innerHeight(); footerHeight = self.context.$footer.innerHeight(); containerHeight = widgetHeight - headerHeight - footerHeight; // if overlaying the footer, don't subtract out its height if ( options.overlayFooter ) { containerHeight += footerHeight; } // set the height of the content to fill the vertical space self.context.$container.innerHeight( containerHeight ); // if overlaying the footer, set a negative margin on the footer equal to its height, // to pull it back into view if ( options.overlayFooter ) { self.context.$footer.css( "margin-top", -1 * footerHeight ); } } |
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 Position() { var WidgetHeight, // BAD (doesn't start with a lowercase letter) headerheight, // BAD (doesn't capitalize "height") footer_Height, // BAD (doesn't omit underscores) container_height; // BAD (doesn't omit underscores) WidgetHeight = self.context.$widget.innerHeight(); headerheight = self.context.$header.innerHeight(); footer_Height = self.context.$footer.innerHeight(); container_height = WidgetHeight - headerheight - footer_Height; // if overlaying the footer, don't subtract out its height if ( options.overlayFooter ) { container_height += footer_Height; } // set the height of the content to fill the vertical space self.context.$container.innerHeight( container_height ); // if overlaying the footer, set a negative margin on the footer equal to its height, // to pull it back into view if ( options.overlayFooter ) { self.context.$footer.css( "margin-top", -1 * footer_Height ); } } |
"Apps Hungarian" notation is acceptable; "System Hungarian" is not
"Apps Hungarian" notation refers to the practice of embedding the purpose of a variable in its name. This is acceptable. "System Hungarian" notation refers to the practice of embedding the data type of a variable in its name. This is not acceptable.
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 Position() { var widgetHeight, // GOOD headerHeight, footerHeight, containerHeight; widgetHeight = self.context.$widget.innerHeight(); headerHeight = self.context.$header.innerHeight(); footerHeight = self.context.$footer.innerHeight(); containerHeight = widgetHeight - headerHeight - footerHeight; // if overlaying the footer, don't subtract out its height if ( options.overlayFooter ) { containerHeight += footerHeight; } // set the height of the content to fill the vertical space self.context.$container.innerHeight( containerHeight ); // if overlaying the footer, set a negative margin on the footer equal to its height, // to pull it back into view if ( options.overlayFooter ) { self.context.$footer.css( "margin-top", -1 * footerHeight ); } } |
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 Position() { var nWidgetHeight, // BAD nHheaderHeight, nFooterHeight, nContainerHeight; nWidgetHeight = self.context.$widget.innerHeight(); nHheaderHeight = self.context.$header.innerHeight(); nFooterHeight = self.context.$footer.innerHeight(); nContainerHeight = nWidgetHeight - nHheaderHeight - nFooterHeight; // if overlaying the footer, don't subtract out its height if ( options.overlayFooter ) { nContainerHeight += nFooterHeight; } // set the height of the content to fill the vertical space self.context.$container.innerHeight( nContainerHeight ); // if overlaying the footer, set a negative margin on the footer equal to its height, // to pull it back into view if ( options.overlayFooter ) { self.context.$footer.css( "margin-top", -1 * nFooterHeight ); } } |
Next time
Whitespace conventions.