JavaScript Tips, Tricks & Best Practices

For meltmedia Marketing Sites

Not going to go over too much JS syntax. More of things that you might see or need to do when developing JS for our marketing sites

File Organization For Marketing Sites

  • Most JS code can be divided into 3 categories:
  1. Files that need to be on every page
  2. Files used by multiple components but not all pages
  3. Files used by only one component
Lots of possible overlap here. Some code for only one component can be on every page. Think about logical groups

Files For All Pages

Include on all the pages!
  • Files go in /js
  • Referenced by jsGlobal in themeName.json from site root
  • Examples: libraries
  {
    "name" : "themeName",
    "jsGlobal" : [
    	"js/prototype.js",
    	"js/jquery-1.5.1.min.js",
    	"js/jquery.noconflict.js",
    	"js/jquery-ui-1.8.12.custom.min.js"
    ]
  }
	

There may be other code that needs to be executed on every page but this should be for files whose logical group is "site-wide" rather than belonging to a plugin.

Files Shared By Multiple Components

  • Files go in /js
  • Referenced by jsGlobal in componentName.json from site root
  • Examples: shared plugins, video players, etc
  {
    "componentId" : "componentName",
    "jsGlobal" : [
      "js/jakebox.js",
      "js/jqModal.js"
    ]
  }
	

This code should be more likely to be associated with multiple plugins. Some code can straddle the line between these two. Make the best decision possible based on the use of the script on the current site.

Files Specific to a Component

  • Files go in /lib/components/componentName/js
  • Referenced by js in componentName.json from component root
  {
    "componentId" : "componentName",
    "jsGlobal" : [
      "js/jakebox.js",
      "js/jqModal.js"
    ],
    "js" : ["js/mediaCenterComponent.js"]
  }
	

Rule to be safe: If you are writing code for a plugin, put it here

Does File Order Matter?

  • Yes. Whenever possible use this as a guide to what will come first
  1. Scripts that change visible nature of page
  2. Scripts that directly affect content areas
  3. Scripts that directly affect navigation, headers, footers
  4. Scripts that add event handlers
  5. Third party tracking, analytics

Note: you will still need to include any libraries/plugins before you use them elsewhere

  1. pngfixes, font adjustments
  2. superscript or glossary plugins
  3. suckerfish
  4. Anything you will click on

Avoid Script Tags

  • Put it in a file! Avoid <script> tags in your <body>
    <body>
      <script type="text/javascript">
        /* Any code in here will
        block page rendering until it's done */
      </script>
    </body>
	

This is easy to do with our component system since everything has a body.html but please refrain

Avoid Globals

Use global variables and you will be forever alone
  • Don't make it global! Avoid polluting the global namespace with variables
    var x = 0, y = 10;
    function doSomething(x) { }
    function doSomethingElse(y) { }
	
  • That's 4 declarations to the global namespace
  • That's twice as many as jQuery has for ~9000 lines of code

Object Literals

  • Don't worry! There are better ways!
  • Does it need to be accessed by other code on the site? Use an object literal
Did you use just one global variable? F*** Yea!
  var siteName = {
    config: {
      x: 0,
      y: 10
    },
    doSomething: function(x) {},
    doSomethingElse: function(y) {}
  };
  // Later...
  siteName.anotherFunction = function() {};
	
These can be nested as far as you want, but don't do it more than is necessary or logical

Use a SEAF

  • If it doesn't need to be accessed by other code wrap it in a self executing anonymous function
  (function() {
    var imLocal = true,
        meToo = 'wooHoo';

    function doSomething() {}
    function anotherFunc() {}
  })();
	
This is similar to wrapping code in $(document).ready(). It keeps declarations out of the global scope.

Pass window to your SEAF

  • Passing oft used variables to your SEAF makes them local which has many benefits
  (function(window, $) {
    /* Using local window like a boss
    Speeds up lookups
    Better gzip and minification */
  })(window, jQuery);
	
Not absolutely necessary, but a good practice and good to know what it is when you see it. Might not be necessary if all your code is already wrapped in a $(document).ready

Make variables not war

  • Always use the var keyword (if you don't, it's global!)
  • Use var to declare multiple variables
  /* Bad */
  var count = 0;
  var length = 10;
  var words = 'Words words words';

  /* Good */
  var count = 0,
      length = 10,
      words = 'Words words words';
  
Improves readability, best practices to put single var declaration at the top of each function

Cache Once, Use Whenever

  • Make a variable for anything that will be used often
  if ($('#header').is(':visible')) {
    $('#header').hide();
  } else {
    $('#header').show();
  }
  // Instead...
  var $header = $('#header');
  if ($header.is(':visible')) {
    $header.hide();
  } else {
    $header.show();
  }
  
Doing DOM lookups, calculations is expensive. Store the result, be happy

Run in a Browser

  • window.onload vs $(document).ready()
  • window.onload will not run until all resources have been loaded (including images)
  • $(document).ready() will run once the DOM is ready (much sooner)
  window.onload = function() {
    /* I'm going to wait for everything on the page */
  };

  $(document).ready(function() {
    /* I will run once the DOM is ready to be worked with */
  });
  

Progressive Enhancement

  • JavaScript should be used to enhance, not create functionality*
  /* Bad, bad, bad
  Nothing will happen without JavaScript!
  */
  <!-- HTML -->
  <a href="#" onclick="openSafetyInformation();">Safety</a>

  /* JS */
  function openSafetyInformation() {
    $('#safety-info').show();
    return false;
  }
  

Progressive Enhancement

  /* Good */
  <!-- HTML -->
  <a href="safety.html" id="safety-btn">Safety</a>

  /* JS overrides normal link behavior */
  $('#safety-btn').click(function() {
    $('#safety').load('safety.html', function() {
      $(this).show();
    });
  });
  

*Note: Obviously some things can't be done without JavaScript but a fallback should be in place whenever possible

Don't Do Too Much With JavaScript

Y U NO LET HTML AND CSS DO THEIR JOBS?
  • JavaScript can write your HTML, add CSS to it and make it interactive
  /* You know how to
  do this correctly */
  var emailForm = $('<form/>')
    .attr('action', '/search')
    .css({'padding':'10px','background':'#000'});
  var toLabel = $('<label/>')
    .text('To')
    .css({'border':'1px solid #000'})
    .appendTo(emailForm);
  emailForm.appendTo('#emailArea');
  

Write all your css classes, use JavaScript to toggle them

Vonnegut Was Wrong; Use Semicolons

  • Semicolons are not required but leaving them out can cause unexpected results
  • Always use curly braces
  • The use of both improve readability, remove ambiguity
  /* This is valid but frowned upon */
  if (testCondition) runThisCode()

  /* How about this instead? */
  if (testCondition) {
    runThisCode();
  }
  

jQuery Awesomesauce

IE6 has us. Save us Mario!
  • jQuery = $;
  • We are the Princess, jQuery is Mario, IE6 is Bowser
  • Top 3 Features of jQuery To Make Your JS Life Easier
    1. Selectors: CSS 1-3 + MOAR!
    2. Chaining: Use multiple methods on one element
    3. Ajax: It used to be hard, now it's one line

jQuery Selectors

  • List of Selectors
  • Difficult, complicated to implement these cross-browser in pure JavaScript
  • jQuery helps us out
  $('div.myClass'); // All divs with a class of 'myClass'
  $('div:animated'); // All divs that are being animated
  $('input[name*="man"]'); /* All inputs with a name
    attribute that contains 'man' */
  $('p:hidden'); // All paragraphs that are hidden
  $('td:eq(2)'); // The third td
  

jQuery Chaining

  • John Resign said it was his biggest AHA! moment when creating jQuery
  • Allows you to chain jQuery methods since most of them return themselves
  /* Example Time */
  $('#header') // Find element with id of 'header'
  .slideDown(400) // Animate it sliding down over 400ms
  .css('background','red') // Change background to red
  .addClass('active') // Add class active
  .wrap('<div/>'); // Wrap it in a div

  /* Could also be all on one line */
  

jQuery Ajax

  • $.ajax() Cross-browser, simple, powerful
  • Shortcut methods for almost anything
  • Easy callbacks
  // GET (shortcut method) all the raw data from test.html
  $.get('test.html', function(data) {
    // This will fire once the call is finished
    console.log(data);
  });

  // Grab all data from a form, POST to test.php
  $.post("test.php", $('#formId').serialize() );
  

Tools

Web Inspector: breakpoints, console