Javascript - Useful Tips & Tricks

We updated the version of jQuery used by our CMS recently (1.3 -> 1.4) and noticed a stylesheet written to the page header after it loaded was being ignored by IE7/8.

Turns out that if we wrote the <link/> tag to the header first, then wrote its attributes, everything started working again.

Worked in jQuery v1.3:

jQuery('<link rel="stylesheet" type="text/css" href="myStyles.css" />').appendTo('head');

Works in jQuery v1.4:

var cssLink = jQuery('<link />').appendTo(jQuery('head'));
cssLink.attr({
  rel: 'stylesheet',
  href: 'myStyles.css'
});

Sometimes other scripting libraries that you use may conflict with jQuery, so you need a way to use both of them without them conflicting.

jQuery has a useful noConflict mode that helps with that.

Load the jQuery library, then tell jQuery to go in to noConflict mode.


<script src="js/jquery.js"></script>
<script>jQuery.noConflict();</script>

Now the $ symbol is not automatically used by jQuery anymore.

It is possible though to still use $ for your jQuery code. You just have to provide it as a function parameter to the jQuery callback.


<script src="js/jquery.js"></script>
<script src="js/script.js"></script>

js/script.js


jQuery.noConflict();
jQuery(function ($) {
    // jQuery code in here
});

When a strict doctype is not used, I.E allows a name parameter as well as ID, and also treats the parameter as case insensitive.
This version suppresses that behaviour:

function $( id )
{
  var elem = document.getElementById( id );
   
  return elem && elem.id === id ? elem : null;
}

If you just want to repair document.getElementById:


if( !document.GETELEMENTBYID )
{ 
 document.GETELEMENTBYID = document.getElementById;

 document.getElementById = function( id )
 {
  var elem = document.GETELEMENTBYID( id );
   
  return elem && elem.id === id ? elem : null;
 }
}

It should be noted that this technique must not be used when the length of the array/collection is likely to be changed by the statements executed within the loop, as the change will not be reflected in the value of len.

Handling Forms

Unique Identifiers

Accessing and controlling forms is best achieved by placing a unique identifier on the form element, so that from there you can use the form’s elements collection to access all of the form fields within that form.

Do not use a name attribute to identify the form. That is a technique from the previous century that died out along with using named anchors. Name attributes should only be used to identify fields within a form that are to be submitted.

Use an id attribute to provide a unique identifier for the form:


<form id="mariachiBand">
    <p><label>
        <input type="checkbox" name="mariachi">
        Allow Mariachi band to interrupt our meal?
    </label></p>
    <p><input type="submit"></p>
</form>

There is no requirement to place unique identifiers on the individual form fields. The form contains a collection called elements, which contains all of the form fields.

Associating Events

Once the form exists, use scripting to attach events on to either the form itself, or on to elements of the form. This can be best achieved by putting your script at the end of the body, just before the </body> tag.


<html>
<head>
...
</head>
<body>
...
<script src="script.js"></script>
</body>
</html>

The scripting can then easily retrieve a reference to the form element, and uses that to associate functions to the events of the form, or to elements of the form.


var form = document.getElementById('mariachiBand');
form.onsubmit = ...

Attaching Functions

Both anonymous functions and named functions can be attached to events.

This is an anonymous function being attached to the onsubmit event of the form:


form.onsubmit = function () {
    var form = this;
    if (form.elements.mariachi.checked) {
        return confirm('Are you absolutely certain that you want a Mariachi band?'); // prevent form submission if need be
    }
};

When attaching named events, it is only the name of the function that you use. Do not use the parenthesis after the name as that will invoke the function, causing only the returned value from the function to be assigned.


function mariachiHandler() {
    var checkbox = this,
        bandname = this.bandname;
    if (!checkbox.checked) {
        return alert(bandname + ' regret your decision.');
    }
}
var mariachi = form.elements.mariachi;
mariachi.bandName = 'The Broken Strings';
mariachi.onclick = mariachiHandler;

Issues with Parameters

When passing parameters to the functions, don’t try to pass the parameters directly since that will only result in the returned value from the function being assigned.


var mariachi = form.elements.mariachi;
mariachi.onclick = mariachiHandler('Broken Strings'); // problem: no function is assigned to the event.
// Only the returned value from the function is assigned, resulting in the event doing nothing.

You can create a function directly, and from inside of that function invoke your function with its parameters, but you need to then pay special attention to the this keyword:


function mariachiHandler(bandname) {
    ...
}
var mariachi = form.elements.mariachi;
mariachi.onclick = function () {
    return mariachiHandler('Broken Strings'); // problem: the this keyword is not retained in the function call
};

Retaining Context to the Function

So to retain the this keyword while also passing parameters to the function, you can use the .call() method to invoke the function from within the correct context.


function mariachiHandler(bandname) {
    ...
}
var mariachi = form.elements.mariachi;
mariachi.onclick = function () {
    return mariachiHandler.call(this, 'Broken Strings');
};

You can also automate this by creating a function that does much of the dirty work for you, where the .apply() method is used to pass a context and parameters to a function.


function mariachiHandler(bandname) {
    var checkbox = this;
    if (!checkbox.checked) {
        return alert(bandname + ' regret your decision.');
    }
}
function paramsToHandler(handler, params) {
    return function () {
        handler.apply(this, params);
    };
}
var mariachi = form.elements.mariachi;
mariachi.onclick = paramsToHandler(mariachiHandler, ['Broken Strings']);

If you don’t want to use an array when passing a single parameter, the handlerWithParams will need to be capable of determining if an array has been passed or not.


function paramsToHandler(handler, params) {
    if (params.constructor.toString().indexOf('Array') === -1) {
        params = [params];
    }
    return handler.apply(this, params);
}
var mariachi = form.elements.mariachi;
mariachi.onclick = paramsToHandler(mariachiHandler, 'Broken Strings');

Here are some Javascript tips I discovered when writing a free game:

  1. You can remove an element from an array with ‘splice’. For example:

    array.splice(index, 1); // remove item at index

usually the built-in array functions on arrays return a new array.

  1. A CSS style attribute that is not set has a value of ‘’, an empty string. To get rid of one of your style settings, set it ‘’.

  2. You cannot do really slick and fast animations with simple Javascript and dynamic HTML without the browser becoming unresponsive or maybe missing out steps.

You need to pause, maybe for longer than 50 milliseconds, to let the browser handle your mouse clicks and refresh the screen.

You could try using the ‘canvas’ element, but I am not sure if Internet Explorer supports it.

  1. You can of course do transparency yourself - just take a (weighted) average of the red, green and blue values separately.

Older browsers such as Internet Explorer 6 may not support an ‘opacity’ setting, particularly if set dynamically.

  1. Dividing a number by zero gives the value ‘Number.POSITIVE_INFINITY’ and does not cause an error.

  2. My suggestions for optimising Javascript would be to think carefully about what algorithms you use and try hard not to repeatedly execute any code unnecessarily.

Simple examples of these are that I use a binary search to look up values in a long list, and only make changes related to some settings values once the user has finally left the settings screen so the user can change the values within the settings screen many times and still get a quick response.

  1. You can add a ‘toString()’ member function to your classes to show the values of their instances nicely. For example:

    myClass.prototype.toString =
    function() { return ‘(’ + this.a + ', ’ + this.i + ‘)’; }

If the instances are in an array, Javascript will show each instance nicely in a list.

This is useful when debugging, in alert messages and writing trace output.

  1. You do not need to put brackets around the arguments to the ‘typeof’ and ‘instanceof’ operators.

It is really ‘typeof v’ not ‘typeof(v)’

  1. I extend the built-in ‘Array’ object with my own functions and so if I use a ‘for in’ loop to go through array elements then my extensions are included.

To get round this, I recently tried a suggestion on the Internet and used Javascript’s internal ‘Object’ class directly rather than using arrays at all.

For example: var o = {}; o[‘a’] = 4;

  1. I understand that all numbers are stored as floating point numbers in Javascript and that there is no integer type.

I have read that the bit manipulation operators in Javascript can be slow.

This may be because the floating point numbers have to be converted to integers and then converted back.

Here are some more Javascript tips I learnt when writing a free game:

  1. If global variables are used many times in a function, it is faster to make local copies of them.

  2. Check just once for features that vary between browsers. For example, finding where you click the mouse by using either ‘event.target’ or ‘event.srcElement’

  3. In a function of an object, inner functions do not have the ‘this’ variable available to them. ‘this’ refers to the current instance of the object. A simple way round this is to set a variable ‘that’ to be ‘this’ in the outer function and use the variable ‘that’ in any inner functions.

  4. Javascript acts as though it is single threaded, so you do not need to do much locking. While your current functions are running, Javascript will ignore any mouse clicks and any code starting from a timeout. I do sometimes use a lock to hold onto control during pauses in animations. As Javascript is single threaded, the sequence of testing a value and setting a value is atomic.

Also when Javascript shows an alert box, the script completely stops. All threads running freeze.

  1. Remember that neatly indenting your HTML adds text elements which can get in the way when your are going through the document tree with, for example, ‘nextSibling’ or ‘previousSibling’. You might like to squash up the HTML.

  2. To set the ‘for’ property of a HTML ‘label’ in Javascript, you set the ‘htmlFor’ property. Otherwise Javascript confuses this with the ‘for’ loop keyword. My Konqueror browser lets you use ‘for’ in the ‘setAttribute()’ function for this but Internet Explorer does not.

In Javascript you set an HTML element’s ‘className’ not ‘class’ to add the element to a CSS stylesheet class. Also remember that you set the ‘className’ on the HTML element and not in the elements ‘style’ object.

  1. Remember that the user can scroll through the page. When you position a HTML element absolutely, add the amount scrolled. I use the value of ‘document.body.scrollTop’.

  2. Coding like this:

    msg = x +
    y;

rather than:

msg = x
      + y;

may help the Javascript interpreter to parse your code faster as newlines can end statements

  1. I found ‘JSHint’, the static code analyser, to be very useful.

It seems more flexible than ‘JSLint’ on which it is based. As an example, ‘JSLint’ stops when it comes to places where I declare variables inside ‘for’ loops, for example: ‘for (var i = 0; i < 3; i++)’.

JSHint pointed out that:

a) I had forgotten to end many statements with a semicolon. In particular I had used the form ‘obj.prototype.func = (){}’ but missed off the semicolon at the end

b) I had sometimes forgotten to declare variables as local variables with a ‘var’, leaving them to be global variables which might be slower to look up

c) I had defined variables more than once in functions with multiple ‘var’ statements

d) I had declared some classes (objects) and variables below where they were used in the source file. Sometimes I had something like:

function func() {
    function subFunc() { i = 3; }
        var i;
}

where it might be slightly better to declare the variable ‘i’ at the start of the outer function

e) I still occasionally used ‘==’ and ‘!=’ rather than ‘===’ and ‘!==’. The former may convert its arguments to a different type leading to subtle errors

I had a few minor problems with JSHint:

a) it expects you to restrict the results of ‘for in’ statements by using the ‘hasOwnProperty()’ method. I was just worried about my extensions to the built-in Array type being returned with the value of associative arrays and so just checked to see if the values had the ‘function’ type

b) it did not like me sometimes letting code ‘fall through’ ‘case’ statement in ‘switch’ blocks

c) it warned when I put the ‘default’ statement of a ‘switch’ block in the middle of other ‘case’ statements

e) it would say I was using a variable ‘out of scope’ when I declared it in an ‘if’ block and later used it in a similar ‘if’ block

You can increase the number of errors that the JSHint website shows if you include a comment like the following at the top of your script:

/*jshint maxerr: 500 */

It is best to use ‘JSHint’ as you are writing your code so you can adjust your coding style. If you wait until you finished, like I did, you will get a huge number of warnings.

That would be due to the variable not being contained within the for loop. That might be your intention, but in reality the variable declaration is hoisted to the start of the function, which is why you’re asked to make your code consistent to that.

The reason why it’s preferred to define them in one var statement is that allowing multiple ones leads to the temptation to place them in different places throughout your code.
Due to the hoisting effect on variable declaration, it’s best to declare them in the one var statement.
Another useful side-effect of declaring them in one statement is that it makes it easier to see if you’re using too many variables, which can lead to the realization that you should split things up in to separate functions.[/quote]

That’s the hoisting effect once again.

You should be aware that extending native objects is a big no-no, because you can’t guarantee that someone else’s similar extension to the same object will clobber the one you made earlier.

With for…in, the preferred technique is:


for (key in foo) {
    if (foo.hasOwnProperty(key)) {
        // do stuff
    }
}

More advanced code might use the .keys() and [url=“https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach”].forEach() methods instead. For example:


Object.keys(foo).forEach(function (key, i, arr) {
    // do stuff
});

Douglas Crockford has a wonderful piece about this, where when someone brought this up to him he considered it to beneficial to have it falling through.
The next day that same person returned to him with a bug report in Crockford’s code, caused by falling through a case statement.
In that moment Crockford achieved enlightenment. video (from 20:21)

The trouble with that is in long switch/case sections you may look at the end and see there’s none there, resulting in you trying to add a second default section to the same switch statement. Always put the default section at the end and you’ll never have to face that problem.

Declare all variables at the start of the function, and you’ll never face that problem.

Here are some more things I have learnt whilst writing a free game:

  1. Some programmers say that it is better to use the expression:

    typeof objectProperty === ‘undefined’

rather than:

objectProperty === undefined

because:

  • you can confusingly create a variable called ‘undefined’ or give a value to Javascript’s ‘undefined’ variable

  • you can use the first version with simple Javascript variables that are not set

Also notice that the expression:

null == undefined

is ‘true’, as Javascript treats a ‘null’ value quite like an ‘undefined’ one

  1. I have read that it is best not to use the ‘caller’ property of functions

Using it may make it difficult for Javascript to optimise your code by ‘inlining’ the functions.

You can find out other ways to help any optimisation by reading about the new ‘strict mode’ for Javascript

  1. I noticed that Internet Explorer (IE) does not allow you to extend HTML elements through their ‘prototype’. I understand that IE generally handles HTML elements a little differently to objects of the Javascript language

  2. I shorten some built-in function names like this:

    Array.prototype.p = Array.prototype.push

I do not change the source code but make the changes in my ‘minimising’ scripts.

If you use a ‘for in’ loop on arrays, you will need to stop the alias appearing by using the ‘hasOwnProperty()’ function. Any libraries you use will need to do this too

  1. If you miss out an element in a list of array elements, e.g. ‘a = [1,3]’, then you get an element with a value of ‘undefined’.

I typed this by mistake and got an error in my code

What can work better is to define undefined as a part of your code wrapper.

For example:


(function (window, document, undefined) {
    ...
}(this, this.document);

That way you have a known good variable for undefined, that cannot be tampered with by other code that runs before yours.

The issue with caller is that it reduces security. It’s also non-standard in ES3, so is being defined as a part of the ES5 specs, even though strictly speaking it shouldn’t be used.

This is due to IE using their own separate language called JScript, which is similar to but not actually JavaScript.

for…in loops should always use hasOwnProperty to ensure that you’re working only with properties of that object, and not inherited properties instead.

With ES5 you can instead use the Keys method to get the keys of an object, so that you can more easily loop over those instead.

This is also a common cause of issues in Internet Explorer, when people leave a trailing comma on an array list, for that trailing comma results in IE placing an undefined item at the end of the array.

Not allowed in strict mode:

<script type="text/javascript">

"use strict";

with(Math)  
{
  myVar = abs(sin(x) * PI + cos(y) / E);
  // compare to
  // myVar = Math.abs(Math.sin(x) * Math.PI + Math.cos(y) / Math.E);
}

</script>

Is sin(x) * PI really a useful example? What would that be used for?

The pedant in me wants to find either PI * 2 and replace that with TAU for a full circle, or to find PI / 2 and replace that with TAU / 4 to represent a quarter of a circle. This helps to aid an understanding of what is going on.

PIr^2 doesn’t help you to understand what is going on, whereas (TAUrr)/2 is the definate integral of a circle’s circumference. There’s a direct correlation between the circumference and the area, between TAUr and (TAUr^2)/2, that helps you to understand what is happening from one to the other. Draw a simple graph of the circumference, from (0,0) to (r, C) and take the area under the line. TAUr^2 is the area of a rectangle, and half of that is the triangle from (0,0) to (r,C). That’s the area of a circle.

With PIr^2 you don’t gain any of that understanding, for it’s a simplification of (2PI*r^2)/2 where the 2’s are cancelled out. But I digress.

If the formula is being used for a contour plot of some kind, I would instead use sin(x) * TAU * xScalingFactor :slight_smile:

When using the with statement, you also end up with troubles when using:


var min = Math.min(Math.sin(x) + Math.cos(y));

Because how is the computer to determine which min is being referred to? The math one or the local variable one?

Anyway - if you do want to simplify things when using heavy math, the preferred way would be to declare the ones you want to shortcut more explicitly, so that it’s clear where they are coming from.


(function () {
    'use strict';
    var abs = Math.abs,
        sin = Math.sin,
        cos = Math.cos,
        PI = Math.TAU,
        E = Math.E;

    function calculateGraphingPoint(x, y, xScale, yScale) {
        xScale = xScale || 1;
        yScale = yScale || 1;
        return abs(sin(x) * TAU * xScale + cos(y) / E * yScale);
    }
    ...
    point[x][y] = calculateGraphingPoint(x, y, 0.5);
}());