Skip to content

Instantly share code, notes, and snippets.

@jcreamer898
Created January 10, 2012 20:34
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jcreamer898/1591029 to your computer and use it in GitHub Desktop.
Save jcreamer898/1591029 to your computer and use it in GitHub Desktop.
Javascript Standards and Patterns

From Javascript Web Applications by Alex MacCaw,

"The secret to making large JavaScript applications is not to make large JavaScript applications. Instead, you should decouple your application into a series of fairly independent components. The mistake developers often make is creating applications with a lot of interdepenency, with huge linear JavaScript files generating a slew of HTML tags. These sorts of applications are difficult to maintain and extend, so they should be avoided at all costs. Paying a bit of attention to an applications structure when you start building it can make a big difference to the end result. Ignore any preconceived notions you have about JavaScript and treat it like the object-oriented language that it is. Use classes, ineritance, objects, and patterns in the same way you would if you were building an application in another language such as Python or Ruby. Architecture is critical to server-side applications, so why shouldn't the same apply to client-side apps."

Our application is a JavaScript intensive application. Client-side scripting is as important in our application as the C# code that drives it. As a team we have developed coding standards to adhere to in order to keep the application maintainable, testable, and usable.

Code Standards

Maintainable code means code that:
• Is readable
• Is consistent
• Is predictable
• Looks as if it was written by the same person
• Is documented

General Guidelines

  • Always indent your code to make it pretty (readable, maintainable, etc).
  • Always use semicolons at the end of a line.
  • Test code in mulitple browsers using [Qunit](Testing with Qunit).
  • Watch out for the keyword class. It is a reserved word in some browsers (Cough...IE...Cough...).
  • For the love of God and all that is good and holy in this world, comment your code. It makes it so much easier to understand for the next developer who has to fix your mistakes or add to your code down the road. Use JSDoc for generating documentation.
  • undefined == null // Believe it or not, this is true.

###Variables

Use camelCase for variables and functions.

var myVariable = "Variable";
var myFunction = function(){
    console.log(myVariable)
};

When initializing objects...

var myArray = [] // Do this
var myarray = new Array; // Not this

var myObject = {} // Do this
var myObject = new Object; // Not this

Use PascalCase for namespaces and object constructors (Things that require a new operator).

var MyNamespace = {};
var MyNamespace.MyClass = function(){
    var privateFunction = function(){
        return "Something Private";
    };

    this.publicProperty = "Default Property";
    this.publicFunction = function(){
        return "Do something with" + this.publicProperty + "or call" + privateFunction();
    };
    return this;
};
var MyNamespace.staticFunction = function(i){
    console.log(i * 2);
};

var fail = MyNamespace.MyClass().publicFunction();    // This won't work!
var notFail = new MyNamespace.MyClass().publicFunction();    // This will though

MyNamespace.staticFunction(2);    // Writes 4 to the console.

Always use var before declaring variables. And watch out, buecause variables in JavaScript are Global by default. This means...

thisBadGlobal = "hello"; 
console.log( thisBadGlobal ); // "hello"
console.log( window.thisBadGlobal ); // "hello" 
console.log( this.thisBadGlobal ); // "hello"

Is a prefectly legal thing to do. But this means you can run into naming conflicts with other libraries. Also, this is bad...

function doSomething(){
    //...stuff...
    result = stuffThatJustHappened;
    return result;
}

Now result has just been added to the global namespace because it was not prefixed with a var. Also, don't do this...

function doSomething(){    
    var a = b = 0;
}

Instead do this because this ensures that a and b are going to stay local. In the above example b would end up being global since it does not have it's own var declaration. Declare variables like this...

function doSomething(){    
    var a = 2, 
        b = 2, 
        c = a * b, 
        d = c + 4,
        result = 0;

    result = a + b + c + d; // result = 12, and it stays inside the scope of doSomething :)
    return result;
}

Keep ALL var declarations inside of a function at the top of the function, and initialize the variables when possible. This helps keep the code clean and let's you know what scope different variables belong in, it makes it easy to find all the variables for a function, and it helps to stop using variables that are undefined.

Instead of introducing too many variables into the global namespace, utilize namespacing like this.

var MyNamespace = {}
MyNamespace.MyClass = function(){ 
    this.doStuff = function(){
        console.log("My class") 
    }
}
var myClass = new MyNamespace.MyClass().doStuff() // "My class"  

Another good practice when defining namespaces is to check if the namespace is undefined; especially when utilizing the same namespace in different files...

var MyNamespace = MyNamespace || {};

When declaring constant variables, use all caps for the variable name.

var GLOBAL_VARIABLE = "Something that is global"
window.ANOTHER_GLOBAL_VARIABLE = "Another variable that is global."  

Cache long names...

var forms = document.forms;
var shorterNamespace = MyNamespace.ThatGoes.OnForever.AndEver;

Create default options for an object...

var myObject = function(o){
    var options = {
        color: blue,
        width: 100
    };
    options = $.extend({}, options, o);
    // Now do stuff...
};
myObject({ color: red }); // Now the options for myObject are { color: red, width: 100 }

For Loops

When using for loops, it is a good idea to cache the length of the object being iterated over...

for(var i = 0, length = something.length; i < length; i++){
    console.log(something[i]);
}

This is a useful standard especially when iterating over lengthy DOM elements, and it also increases performance by caching the length.

Type Comparisons

Although JavaScript is a Dynamic language, there are still a few built in types.

var num = 1;
console.log(typeof num) // "number"

var myString = "My string";
console.log(typeof myString); // "string"

var myObject = {};
console.log(typeof myObject); // "object"

There IS a difference between == and ===. === does a type compare when comparing the two things...

var num = 3;
var stringNum = "3";
	
console.log(num == stringNum); // True
console.log(num === stringNum); // False because stringNum is a string, while num is a number  

Pretty much just use === most of the time.

Patterns

Use anonymous closures when private functions are needed so as not to clog the global namespace...

(function(global){
    var somethingToDo = function(){
        // Do something
        return "I did something!";
    }

    global.anotherThingToDo = function(){
        console.log(somethingToDo());
    }
}(window));
somethingToDo(); // undefined
anotherThingToDo(); // "I did something!"

This concept is similar to a pattern known as The Revealing Module Pattern which is a strong pattern to promote separation of concerns and DRY in JavaScript. You can also use it to create "classes" if you want to call them such a thing...

var MyClassThingy = (function(global){
    var ClassThingy = function(){
        // Setup stuff
    };
    var aPrivateFunction = function(){
        return "I am private!";
    }
    ClassThingy.prototype.anAwesomePublicFunction = function(){
        console.log(aPrivateFunction());
    }

    return ClassThingy;
}());
var instanceOfClassThingy = new MyClassThingy().anAwesomePublicFunction(); // "I am private!"

Or create a "static class"...

var MyStaticClass = (function(global){
    var aPrivateFunction = function(){
        return "I am private again!";
    }
    var anAwesomePublicFunction = function(){
        console.log(aPrivateFunction());
    }

    return {
        publicFunction: anAwesomePublicFunction 
    };
}());
MyStaticClass.publicFunction(); // "I am private again!"

Templating

"It has long been considered bad practice (and computationally expensive) to manually create large blocks of HTML markup in-memory through string concatenation. Developers using this technique often find themselves iterating through their data, wrapping it in nested divs and using outdated techniques such as document.write to inject the 'template' into the DOM. This approach often means keeping scripted markup inline with standard markup, which can quickly become difficult to read and maintain, especially when building large applications."

From https://github.com/addyosmani/backbone-fundamentals

There are many templating frameworks out there all aimed at a single goal of removing big long Html strings from JS. There is built in to the (UnderscoreJS)[http://documentcloud.github.com/underscore/] library, there is (Mustache.js)[mustache.github.com/] and (HandlebarsJS)[http://handlebarsjs.com/].

UnderscoreJS looks like this.

<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.2.2/underscore-min.js"></script>
<script type="text/html" id="template">

        <tr>
            <td>
                <%= data[0] %>
            </td>
            <td>
                <%= data[1] %>
            </td>
            <td>
                <%= data[2] %>
            </td>
        </tr>

</script>
<script>
$(function(){
    var template = _.template($("#template").html());
    $("#ColorChart").append(template({ data: ['Data 1','Data 2','Data 3'] }));
});
</script>

Documentation

An example usage of JSDoc...

/**
* myClass describes a person
* @param {string} name Name of the person
* @param {number} age Age of the person
* @returns An instance of myClass
var myClass = function(name,age){
    this.name = name;
    this.age = age;
}

Here's some more examples...JSDoc Examples

jQuery Tips

  • $(document).ready(function(){ // Yada yada }) is the same as $(function(){ // Yada yada }), which is shorter. So, use the latter of those two.

Performance Tips Slideshow

References

Terse Javascript 101

Terse Javascript 101 Part 2

Lessons from a JavaScript Code Review

Free web book on Javascript Patterns

Javascript Patterns

Google JavaScript Guide

closures

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment