UGTS Document #45 - Last Modified: 8/29/2015 3:23 PM
Javascript Best Practices

Best Practices for Javascript Coding

Javascript is a powerful scripting language that runs in the client's browser.  If you write a lot of Javascript, you will soon discover that there are some best practices that will make your development efforts much easier:

  • JS Files - Always write generic javascript code in .js files and invoke that code from a few lines of non-generic javascript embedded into the pages that need it.  It is much easier to debug javascript in JS files because you have intellisense, syntax highlighting, breakpoints, and if you have a crash, the browser will tell you the exact line number and character where the crash occurred.  Also, having generic javascript code in library files means you only have to write and debug it once, and then you can re-use it wherever you need it. 
  • Classes and Prototypes - Always write object oriented code whenever possible.  Javascript supports enough of object oriented programming that you might as well use it to make your code easier to organize and debug.
  • Variable Declaration - Unlike some scripting languages, you don't have to declare a variable in order to start using it.  However, if you don't, then the browser will implicitly create a GLOBAL member variable on the window object with the name of the variable you forgot to declare, and that will bad for two reasons - it is probably not what you want, and it will clutter the global namespace.  Always explicitly declare your variables. Better yet, 'use strict' to enforce this behavior.
  • Standard Naming Conventions - Javascript is case sensitive.  This (when combined with the Variable Declaration gotcha) can cause you a lot of frustration.  If you mis-spell or mis-capitalize a variable or method name, the browser will not complain to you at all, but will instead create that member or global variable instead of the one you were trying to access.  This causes subtle bugs that are hard to catch.  You can avoid this by keeping the simple naming conventions that most javascript programmers use - camel case for variable names like (thisIsMyVariable), and Pascal case for class names (ThisIsMyClass).
  • Browser Abstraction - Javascript is a standard, but the client browser which runs your javascript is far from standard.  Some browsers are missing features that you might have thought were guaranteed, or those features might have other names.  The number of browsers out there and versions of browsers in wide use is both large and growing all the time.  It's difficult to try to keep up with all of them or to test for a browser by name, but at the same time you must have functions that work reliably and consistently across all browsers.

    The current best way to handle this is to write javascript functions that abstract away these inconsistencies - instead of calling the browser dependent features, you call generic javascript functions instead.  Javascript libraries become the platform upon which the client side code interacts with the browser.  And the code inside thes javascript libraries does not test for browsers by name, but instead checks for existence of variables and methods dynamically to determine if there is support for a given feature.  And if there is no support for the feature in a given browser, the code should fail gracefully.

In writing Javascript libraries, there are also some difficulties which are harder to deal with:

  • Single Pass - Javascript is executed in a single pass from start to finish, and you must define a function before you can call it.  This means that method declarations must occur before the code that calls them.
  • Nested Inclusion - JS files cannot directly include other JS files, but they can make ajax requests and then inject other scripts into the page, either via script tags or through eval().
  • Synchronous Loading - Unlike images and media files, JS files are loaded synchronously.  The browser will wait to download a JS file before showing you the rest of the page, because it will assume that the file is necessary for the proper rending of the page, and the correct order of execution of scripts. When you couple this with the Nested Inclusion gotcha, you start to see that having a lot of little JS files loaded synchronously over a slow link can slow down a website.
  • No JARs - At one time, Netscape supported .jar files to deliver bundles of javascript files in a single zip-compressed file, but support for this in all major browsers ended a long time ago, and now JAR files are used only for Java (not Javascript).
To deal with these difficulties, we can do the following:
  • JS tail - JS files will block a browser from displaying the remainder of a page until the JS content is executed, and JS files will wait for previously referenced CSS files to be loaded. It used to be the case, but is no longer true that CSS files must be linked at the head of the page to display the page properly. This is due to speculative parsing in modern desktop browsers. CSS files can pretty much be placed anywhere in your page unless you have a script that needs to read the CSS before the document is ready.
  • Bundle and GZIP - It may seem like poor practice to pile up all of your script files into a single ten-thousand line script file, because then users must download a really large file that contains a lot of cruft that they may not need, and source code benefits are reduced because only one developer can work on the file at a time, and it goes through hundreds of revisions because the file changes all the time.

    However, this performance penalty is surprisingly easy to handle.  Text files in general compress very well, and browsers can cache script files, so downloading one large super compressed file and caching it once is really better for performance than lots of little files.  Automatic GZIP compression can be enabled on just about all major web servers, and is supported in all major browsers.  In IIS, it can be done through IIS Manager, Web Sites, Properties, Servers tab, check both boxes.  Individual file types to compress can be chosen in the IIS metabase through the metabase settings: 

    W3SVC/Filters/Compression/gzip/HcFileExtensions
    W3SVC/Filters/Compression/gzip/HcScriptFileExtensions


     You will probably want to extend the default definitions of static and script file extensions to include static = JS, and dynamic = ASPX, PHP, etc... if they are not already included.  Then be sure to restart the IIS service.

Javascript and HTML also have a fair number of 'gotchas' that can bite you.  Watch out for:

  • Proper Script tags - The <script> tag cannot be a self-closing tag such as <script/>.  It must ALWAYS have an end tag </script>, even if it is only a link to an external JS file through the src attribute.  If you try to self-close a script tag, the browser will instead treat everything up to the next </script> tag as script, and the 'script' inside this range will almost certainly have compilation errors.  The browser's script engine will silently fail in parsing it, leading it to ignore all the script after the malformed self-closing tag.  This can be really non-obvious when you're wondering why all of the javascript after a certain tag is silently being ignored.

    This reason for this is that only empty/void tags are allowed to be self-closing in HTML, and script is NOT an empty/void tag.  Furthermore, HTML technically has no such thing as a self-closing tag - it is equivalent to a void tag.  XHTML does have self-closing tags, but XHTML is an abandoned (dead) technology and should not be used.  In HTML, either a tag is empty/void (such as BR or HR) and never has any contents, or it always has contents.  Empty tags can be written as self closing, but really the browser is just fixing up the HTML to remove the redundant closing slash for the empty tags and you might as well not self-close them.  Non-empty tags such as P and SCRIPT should always have an explicit closing tag rather than be self-closed.  For most tags other than SCRIPT, this does not cause problems.

    Note also that the script tag can specify the language or type attributes, but they are not necessary (at least according to Douglas Crockford, widely regarded to be an expert on Javascript).  However, if you do specify the type attribute but set it to the wrong type by accident (such as application/javascript instead of text/javascript, you can cause yourself trouble.  It's better to just leave it out and let the browser figure it out by making the correct assumption.