There are a number of considerations that you should take into account when writing JavaScript code. Whether you’re trying to tune your code for better performance or test it for compatibility, these best practices can help your code perform better and be more compatible.
If you’re looking for performance and testing tips for JavaScript coding, read this chapter.
This section includes a number of tips for minimizing your JavaScript application’s memory footprint and helping it perform better.
Release initialization functions. Code that’s called once and never used again can be deleted after its execution. For instance, deleting a window’s onload
handler function releases any memory associated with the function, like this:
var foo = function() |
{ |
// code that makes this function work |
delete foo; |
} |
window.addEventListener('load', foo, false); |
Use delete statements. Whenever you create an object using a new
statement, pair it with a delete
statement. This ensures that all of the memory associated with the object, including its property name, is available for garbage collection. The delete
statement is discussed more in “Freeing Objects.”
Test for an element’s existence. Before using nonstandard elements, check for their existence like this:
if ( "innerHTML" in document.getElementById("someDiv") ) |
{ |
// code that works with innerHTML |
} |
Avoid evaluated statements. Using the eval
function disables performance and memory optimizations in the JavaScript runtime. Consider using function variables, as discussed in “Functions,” in cases where you are passing in lines of code to another function, like setTimeout
or setInterval
.
When creating a JavaScript application, consider these tips for testing your code.
Try multiple browsers. It’s a good practice to try any web-based JavaScript code you write in many browsers. In addition to the version of Safari included with Mac OS X, consider trying your code on these browsers:
WebKit nightly - http://nightly.webkit.org/
Mozilla Firefox - http://www.mozilla.com/firefox/
Opera - http://www.opera.com/
Try other toolkit versions. If you’re using a third-party JavaScript toolkit such as Dojo, MochiKit, or prototype, try different versions of the library to see if your code uses the library properly.
Try a verifier. JavaScript verifiers such as JSLint are useful at pinpointing compatibility problems and cases where the JavaScript code you wrote doesn’t conform to standards.
When writing JavaScript code, it’s good practice to avoid placing code and variables within the global scope of the file. Here are some considerations to consider regarding global scope:
Store data in the DOM tree, in cookies, or in HTML 5 client-side storage objects. The DOM tree, cookies, and HTML 5 client-side storage are good ways to conceal data to avoid conflicts with pages outside your domain. For performance reasons, you should generally limit use of these techniques to infrequently-used data, but any of these three techniques is better than using global variables.
You can store data in the DOM tree like this:
/* Store data in the DOM tree */ |
var DOMobj = document.getElementById('page_globals'); |
DOMobj.setAttribute('foo', myIntegerVar); |
/* for large text content, consider using this: */ |
DOMobj.style.display = "none"; |
DOMobj.innerHTML = myStringVar; |
/* or this: */ |
DOMobj.style.display = "none"; |
if (typeof(DOMobj.innerText) != 'undefined') { |
# Internet Explorer workaround |
DOMobj.innerText = myStringVar; |
} else { |
# Per the W3C standard |
DOMobj.textContent = myStringVar; |
} |
/* Recall the data later */ |
var DOMobj = document.getElementById('page_globals'); |
var myIntegerVar = parseInt(DOMobj.getAttribute('foo')); |
/* Recall the large text data with this: */ |
var myStringVar = DOMobj.innerHTML; |
/* or this: */ |
var myStringVar; |
if (typeof(DOMobj.innerText) != 'undefined') { |
# Internet Explorer workaround |
myStringVar = DOMobj.innerText; |
} else { |
# Per the W3C standard |
myStringVar = DOMobj.textContent; |
} |
Cross-Browser Compatibility Note: Internet Explorer does not support the textContent
attribute on elements. For maximum compatibility, as shown in the previous example, you should support not only the W3C-standard textContent
attribute, but also the IE-specific innerText
attribute.
You can also store data in cookies using the cookie
attribute of the document
object. The syntax for creating and expiring cookies is somewhat complex and easy to get wrong. Thus, this method is discouraged as a global variable alternative unless you already have code for creating and modifying cookies. To learn more about cookies in JavaScript, read http://www.quirksmode.org/js/cookies.html.
Finally, for data that should persist across page loads, you can use HTML 5 client-side storage as described in Safari Client-Side Storage and Offline Applications Programming Guide. Safari 3.1 and later provides both SQL database and local key-value storage.
Use the var keyword. Any variable created without the var
keyword is created at the global scope and is not garbage collected when the function returns (because it doesn’t go out of scope), presenting the opportunity for a memory leak.
Use a global array, global object, or namespace prefix. If you need global variables, use a global object that contains all of the global variables, like this:
var myBulletinBoardAppGlobals = { |
foo: "some value", |
bar: null |
}; |
Or consider using a namespace prefix:
CPWFoo = "some value"; |
CPWBar = null; |
These practices prevent your global variables from colliding with global DOM objects present in the runtime.
Use an initialization function. If you have code that’s run immediately when the JavaScript is loaded, place it in a function that’s called when the window loads, like this:
myBulletinBoardAppGlobals.foo = function() |
{ |
// code that makes this function work |
delete myBulletinBoardAppGlobals.foo; |
} |
window.addEventListener('load', globals.foo, false); |
JavaScript toolkits enhance productivity but often carry a significant memory footprint that may slow down your JavaScript application. When using a toolkit, try to reduce the toolkit’s footprint to just the APIs that you use in your application.
Also, if you’re developing a Dashboard widget, try to avoid bundling the Apple-provided Apple Classes within your widget; instead, follow the instructions provided in Introduction to the Apple Classes.
Last updated: 2009-05-05