JAVASCRIPT STYLE : VARIABLES

Image from Pluralsight

Image from Pluralsight

Introduction

Good code is not just functional, but also elegant. Elegant code must be:

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.

Source: http://www.finitewisdom.com/people/joshua-...