Sie sind auf Seite 1von 139

Imprint

Copyright 2012 Smashing Media GmbH, Freiburg, Germany Version: October 2012 (First published in November 2011) ISBN: 9783943075212

Cover Design: Ricardo Gimenes PR & Press: Stephan Poppe eBook Strategy: Andrew Rogerson & Talita Telma Stckle Technical Editing: Andrew Rogerson Proofreading: Andrew Lobo, Iris Ljesnjanin Idea & Concept: Smashing Media GmbH

Smashing eBook #13JavaScript Essentials 2

ABOUT SMASHING MAGAZINE Smashing Magazine is an online magazine dedicated to Web designers and developers worldwide. Its rigorous quality control and thorough editorial work has gathered a devoted community exceeding half a million subscribers, followers and fans. Each and every published article is carefully prepared, edited, reviewed and curated according to the high quality standards set in Smashing Magazine's own publishing policy. Smashing Magazine publishes articles on a daily basis with topics ranging from business, visual design, typography, front-end as well as back-end development, all the way to usability and user experience design. The magazine is and always has been a professional and independent online publication neither controlled nor inuenced by any third parties, delivering content in the best interest of its readers. These guidelines are continually revised and updated to assure that the quality of the published content is never compromised. ABOUT SMASHING MEDIA GMBH Smashing Media GmbH is one of the world's leading online publishing companies in the eld of Web design. Founded in 2009 by Sven Lennartz and Vitaly Friedman, the company's headquarters is situated in southern Germany, in the sunny city of Freiburg im Breisgau. Smashing Media's lead publication, Smashing Magazine, has gained worldwide attention since its emergence back in 2006, and is supported by the vast, global Smashing community and readership. Smashing Magazine had proven to be a trustworthy online source containing high quality articles on progressive design and coding techniques as well as recent developments in the Web design industry.

Smashing eBook #13JavaScript Essentials 3

About this eBook


It is not always easy for Web developers and designers to make the right decisions when having to choose the right solution. Either while building a complex Web application or even by improving a website, there are countless pre-built solutions available and picking one of them can surely be a burden sometimes. In this eBook we enlighten the most important issues you should pay attention to by all means when selecting a solution, i.e. how stable, easy to customize, usable and accessible it is, whether it can be maintained in the future, what exactly is supported and how you can extend the functionalities on your own. One of the many important issues considered in this Smashing eBook #13: JavaScript Essentials is the importance of reviewing your code and what to avoid when you are implementing in JavaScript. Maintaining strong coding standards and withdrawing your programming away from common errors should be the basic requests for the general quality of your solutions, and the articles we have selected will explain exactly how you can achieve this. One of the sections also advises to have your code reviewed by experts and check whether they may provide other solutions to the problems you're experiencing. Last but not least, you'll get to know the golden rules of JavaScript basic animations better, as well as JSON as a data format along with the native JavaScript functions (Math, Array, String), shortcut notations, and much more. Of course, we couldn't leave out JS events that will make your webApps work, implementation of anonymous functions, module patterns, congurations, interaction with the back end and usage of libraries to specify codes. And for those of you who are rather interested in AJAX, you'll get the information you need in case you've been wanting to turn your content dynamic and searchable. Andrew Rogerson, Smashing eBook Editor

Smashing eBook #13JavaScript Essentials 4

Table of Contents
Seven JavaScript Things I Wish I Knew Much Earlier In My Career Lessons From A Review Of JavaScript Code Find The Right JavaScript Solution With A 7-Step Test Ten Oddities And Secrets About JavaScript The Seven Deadly Sins Of JavaScript Implementation A Quick Look Into The Math Of Animations With JavaScript Searchable Dynamic Content With AJAX Crawling About The Authors

Smashing eBook #13JavaScript Essentials 5

Seven JavaScript
Christian Heilmann

ings I Wish I Knew

Much Earlier In My Career

Ive been writing JavaScript code for much longer than I care to remember. I am very excited about the languages recent success; its good to be a part of that success story. Ive written dozens of articles, book chapters and one full book on the matter, and yet I keep nding new things. Here are some of the aha! moments Ive had in the past, which you can try out rather than waiting for them to come to you by chance.

Shortcut Notations
One of the things I love most about JavaScript now is shortcut notations to generate objects and arrays. So, in the past when we wanted to create an object, we wrote:
var car = new Object(); car.colour = 'red'; car.wheels = 4; car.hubcaps = 'spinning'; car.age = 4;

The same can be achieved with:

Smashing eBook #13JavaScript Essentials 6

var car = { colour:'red', wheels:4, hubcaps:'spinning', age:4 }

Much shorter, and you dont need to repeat the name of the object. Right now, car is ne, but what happens when you use invalidUserInSession? The main gotcha in this notation is IE. Never ever leave a trailing comma before the closing curly brace or youll be in trouble. The other handy shortcut notation is for arrays. The old school way of dening arrays was this:
var moviesThatNeedBetterWriters = new Array( 'Transformers','Transformers2','Avatar','Indiana Jones 4' );

The shorter version of this is:


var moviesThatNeedBetterWriters = [ 'Transformers','Transformers2','Avatar','Indiana Jones 4' ];

The other thing about arrays is that there is no such thing as an associative array. You will nd a lot of code examples that dene the above car example like so:
var car = new Array(); car['colour'] = 'red'; car['wheels'] = 4; car['hubcaps'] = 'spinning'; car['age'] = 4;

This is not Sparta; this is madnessdont bother with this. Associative arrays is a confusing name for objects.

Smashing eBook #13JavaScript Essentials 7

Another very cool shortcut notation is the ternary notation for conditions. So, instead of the following
var direction; if(x < 200){ direction = 1; } else { direction = -1; } You could write a shorter version using the ternary notation: var direction = x < 200 ? 1 : -1;

The true case of the condition is after the question mark, and the other case follows the colon.

JSON As A Data Format


Before I discovered JSON to store data, I did all kinds of crazy things to put content in a JavaScript-ready format: arrays, strings with control characters to split, and other abominations. The creation of JSON by Douglas Crockford changed all that. Using JSON, you can store complex data in a format that is native to JavaScript and doesn't need any extra conversion to be used immediately. JSON is short for "JavaScript Object Notation" and uses both of the shortcuts we covered earlier. So, if I wanted to describe a band, for example, I could do the following:

Smashing eBook #13JavaScript Essentials 8

var band = { "name":"The Red Hot Chili Peppers", "members":[ { "name":"Anthony Kiedis", "role":"lead vocals" }, { "name":"Michael 'Flea' Balzary", "role":"bass guitar, trumpet, backing vocals" }, { "name":"Chad Smith", "role":"drums,percussion" }, { "name":"John Frusciante", "role":"Lead Guitar" } ], "year":"2009" }

You can use JSON directly in JavaScript and, when wrapped in a function call, even as a return format of APIs. This is called JSON-P and is supported by a lot of APIs out there. You can use a data endpoint, returning JSON-P directly in a script node:

Smashing eBook #13JavaScript Essentials 9

<div id="delicious"></div><script> function delicious(o){ var out = '<ul>'; for(var i=0;i<o.length;i++){ out += '<li><a href="' + o[i].u + '">' + o[i].d + '</a></li>'; } out += '</ul>'; document.getElementById('delicious').innerHTML = out; } </script> <script src="http://feeds.delicious.com/v2/json/codepo8/ javascript?count=15&callback=delicious"></script>

This calls the Delicious Web service to get my latest JavaScript bookmarks in JSON format and then displays them as an unordered list. In essence, JSON is probably the most lightweight way of describing complex dataand it runs in a browser. You can even use it in PHP using the json_decode() function.

Native JavaScript Functions (Math, Array And String)


One thing that amazed me is how much easier my life got once I read up thoroughly on the math and string functions of JavaScript. You can use these to avoid a lot of looping and conditions. For example, when I had the task of nding the largest number in an array of numbers, I used to write a loop, like so:

Smashing eBook #13JavaScript Essentials 10

var numbers = [3,342,23,22,124]; var max = 0; for(var i=0;i<numbers.length;i++){ if(numbers[i] > max){ max = numbers[i]; } } alert(max);

This can be achieved without a loop:


var numbers = [3,342,23,22,124]; numbers.sort(function(a,b){return b - a}); alert(numbers[0]);

Notice that you cannot use sort() on a number array because it sorts lexically. There's a good tutorial on sort() here in case you need to know more. Another interesting method is Math.max(). This one returns the largest number from a list of parameters:
Math.max(12,123,3,2,433,4); // returns 433

Because this tests for numbers and returns the largest one, you can use it to test for browser support of certain properties:
var scrollTop= Math.max( doc.documentElement.scrollTop, doc.body.scrollTop );

This works around an Internet Explorer problem. You can read out the scrollTop of the current document, but depending on the DOCTYPE of the document, one or the other property is assigned the value. When you use Math.max() you get the right number because only one of the properties returns one; the other will be undefined. You can read more about shortening JavaScript with math functions here.

Smashing eBook #13JavaScript Essentials 11

Other very powerful functions to manipulate strings are split() and join(). Probably the most powerful example of this is writing a function to attach CSS classes to elements. The thing is, when you add a class to a DOM element, you want to add it either as the rst class or to already existing classes with a space in front of it. When you remove classes, you also need to remove the spaces (which was much more important in the past when some browsers failed to apply classes with trailing spaces). So, the original function would be something like:
function addclass(elm,newclass){ var c = elm.className; elm.className = (c === '') ? newclass : c+' '+newclass; }

You can automate this using the split() and join() methods:
function addclass(elm,newclass){ var classes = elm.className.split(' '); classes.push(newclass); elm.className = classes.join(' '); }

This automatically ensures that classes are space-separated and that yours gets tacked on at the end.

Event Delegation
Events make Web apps work. I love events, especially custom events, which make your products extensible without your needing to touch the core code. The main problem (and actually one of its strengths) is that events are removed from the HTMLyou apply an event listener to a certain element and then it becomes active. Nothing in the HTML indicates that this is the case though. Take this abstraction issue (which is hard for beginners to

Smashing eBook #13JavaScript Essentials 12

wrap their heads around) and the fact that "browsers" such as IE6 have all kind of memory problems and too many events applied to them, and you'll see that not using too many event handlers in a document is wise. This is where event delegation comes in. When an event happens on a certain element and on all the elements above it in the DOM hierarchy, you can simplify your event handling by using a single handler on a parent element, rather than using a lot of handlers. What do I mean by that? Say you want a list of links, and you want to call a function rather than load the links. The HTML would be:
<h2>Great Web resources</h2> <ul id="resources"> <li><a href="http://opera.com/wsc">Opera Web Standards Curriculum</a></li> <li><a href="http://sitepoint.com">Sitepoint</a></li> <li><a href="http://alistapart.com">A List Apart</a></li> <li><a href="http://yuiblog.com">YUI Blog</a></li> <li><a href="http://blameitonthevoices.com">Blame it on the voices</a></li> <li><a href="http://oddlyspecific.com">Oddly specific</a></ li> </ul>

The normal way to apply event handlers here would be to loop through the links:

Smashing eBook #13JavaScript Essentials 13

// Classic event handling example (function(){ var resources = document.getElementById('resources'); var links = resources.getElementsByTagName('a'); var all = links.length; for(var i=0;i<all;i++){ // Attach a listener to each link links[i].addEventListener('click',handler,false); }; function handler(e){ var x = e.target; // Get the link that was clicked alert(x); e.preventDefault(); }; })();

This could also be done with a single event handler:


(function(){ var resources = document.getElementById('resources'); resources.addEventListener('click',handler,false); function handler(e){ var x = e.target; // get the link tha if(x.nodeName.toLowerCase() === 'a'){ alert('Event delegation:' + x); e.preventDefault(); } }; })();

Because the click happens on all the elements in the list, all you need to do is compare the nodeName to the right element that you want to react to the event. Disclaimer: while both of the event examples above work in browsers, they fail in IE6. For IE6, you need to apply an event model other than the W3C one, and this is why we use libraries for these tricks.

Smashing eBook #13JavaScript Essentials 14

The benets of this approach are more than just being able to use a single event handler. Say, for example, you want to add more links dynamically to this list. With event delegation, there is no need to change anything; with simple event handling, you would have to reassign handlers and re-loop the list.

Anonymous Functions And

e Module Pa ern

One of the most annoying things about JavaScript is that it has no scope for variables. Any variable, function, array or object you dene that is not inside another function is global, which means that other scripts on the same page can accessand will usually override them. The workaround is to encapsulate your variables in an anonymous function and call that function immediately after you dene it. For example, the following denition would result in three global variables and two global functions:
var name = 'Chris'; var age = '34'; var status = 'single'; function createMember(){ // [...] } function getMemberDetails(){ // [...] }

Any other script on the page that has a variable named status could cause trouble. If we wrap all of this in a name such as myApplication, then we work around that issue:

Smashing eBook #13JavaScript Essentials 15

var myApplication = function(){ var name = 'Chris'; var age = '34'; var status = 'single'; function createMember(){ // [...] } function getMemberDetails(){ // [...] } }();

This, however, doesn't do anything outside of that function. If this is what you need, then great. You may as well discard the name then:
(function(){ var name = 'Chris'; var age = '34'; var status = 'single'; function createMember(){ // [...] } function getMemberDetails(){ // [...] } })();

If you need to make some of the things reachable to the outside, then you need to change this. In order to reach createMember() or getMemberDetails(), you need to return them to the outside world to make them properties of myApplication:
var myApplication = function(){ var name = 'Chris'; var age = '34'; var status = 'single'; return{ createMember:function(){ // [...]

Smashing eBook #13JavaScript Essentials 16

}, getMemberDetails:function(){ // [...] } } }(); // myApplication.createMember() and // myApplication.getMemberDetails() now works.

This is called a module pattern or singleton. It was mentioned a lot by Douglas Crockford and is used very much in the Yahoo User Interface Library YUI. What ails me about this is that I need to switch syntaxes to make functions or variables available to the outside world. Furthermore, if I want to call one method from another, I have to call it preceded by the myApplication name. So instead, I prefer simply to return pointers to the elements that I want to make public. This even allows me to shorten the names for outside use:

Smashing eBook #13JavaScript Essentials 17

var myApplication = function(){ var name = 'Chris'; var age = '34'; var status = 'single'; function createMember(){ // [...] } function getMemberDetails(){ // [...] } return{ create:createMember, get:getMemberDetails } }(); //myApplication.get() and myApplication.create() now work.

I've called this "revealing module pattern."

Allowing For Conguration


Whenever I've written JavaScript and given it to the world, people have changed it, usually when they wanted it to do things that it couldn't do out of the boxbut also often because I made it too hard for people to change things. The workaround is to add configuration objects to your scripts. I've written about JavaScript conguration objects in detail, but here's the gist: Have an object as part of your whole script called configuration. In it, store all of the things that people will likely change when they use your script: CSS ID and class names; Strings (such as labels) for generated buttons;

Smashing eBook #13JavaScript Essentials 18

Values such as "number of images being displayed," "dimensions of map"; Location, locale and language settings. Return the object as a public property so that people can override it. Most of the time you can do this as a last step in the coding process. I've put together an example in "Five things to do to a script before handing it over to the next developer." In essence, you want to make it easy for people to use your code and alter it to their needs. If you do that, you are much less likely to get confusing emails from people who complain about your scripts and refer to changes that someone else actually did.

Interacting With

e Back End

One of the main things I learned from all my years with JavaScript is that it is a great language with which to make interactive interfaces, but when it comes to crunching numbers and accessing data sources, it can be daunting. Originally, I learned JavaScript to replace Perl because I was sick of copying things to a cgi-bin folder in order to make it work. Later on, I learned that making a back-end language do the main data churning for me, instead of trying to do all in JavaScript, makes more sense with regard to security and language. If I access a Web service, I could get JSON-P as the returned format and do a lot of data conversion on the client, but why should I when I have a server that has a richer way of converting data and that can return the data as JSON or HTML and cache it for me to boot?

Smashing eBook #13JavaScript Essentials 19

So, if you want to use AJAX, learn about HTTP and about writing your own caching and conversion proxy. You will save a lot of time and nerves in the long run.

Browser-Specic Code Is A Waste Of Time. Use Libraries!


When I started Web development, the battle between using document.all and using document.layers as the main way to access the document was still raging. I chose document.layers because I liked the idea of any layer being its own document (and I had written more than enough document.write solutions to last a lifetime). The layer model failed, but so did document.all. When Netscape 6 went all out supporting only the W3C DOM model, I loved it, but end users didn't care. End users just saw that this browser didn't show the majority of the Internets correctly (although it did)the code we produced was what was wrong. We built short-sighted code that supported a state-of-the-art environment, and the funny thing about the state of the art is that it is constantly changing. I've wasted quite some time learning the ins and outs of all of the browsers and working around their issues. Doing this back then secured my career and ensured that I had a great job. But we shouldn't have to go through this trial by re any longer. Libraries such as YUI, jQuery and Dojo are here to help us with this. They take on the problems of browsers by abstracting the pains of poor implementation, inconsistencies and at-out bugs, and relieve us of the chore. Unless you want to beta test a certain browser because you're a big fan, don't x browser issues in your JavaScript solutions, because you are unlikely to ever update the code to remove this x. All you would be doing is adding to the already massive pile of outdated code on the Web.

Smashing eBook #13JavaScript Essentials 20

That said, relying solely on libraries for your core skill is short-sighted. Read up on JavaScript, watch some good videos and tutorials on it, and understand the language. (Tip: closures are God's gift to the JavaScript developer.) Libraries will help you build things quickly, but if you assign a lot of events and effects and need to add a class to every HTML element in the document, then you are doing it wrong.

Resources
In addition to the resources mentioned in this article, also check out the following to learn more about JavaScript itself: Douglas Crockford on JavaScript An in-depth video Lecture series. The Opera Web Standards Curriculum With a detailed section on JavaScript.WordPress Essentials: How To Create A WordPress Plugin

Smashing eBook #13JavaScript Essentials 21

Lessons From A Review Of JavaScript Code


Addy Osmani
Before we start, Id like to pose a question: when was the last time you asked someone to review your code? Reviewing code is possibly the single best technique to improve the overall quality of your solutions, and if youre not actively taking advantage of it, then youre missing out on identifying bugs and hearing suggestions that could make your code better. None of us write 100% bug-free code all of the time, so dont feel theres a stigma attached to seeking help. Some of the most experienced developers in our industry, from framework authors to browser developers, regularly request reviews of their code from others; asking whether something could be tweaked should in no way be considered embarrassing. Reviews are a technique like any other and should be used where possible. Today well look at where to get your code reviewed, how to structure your requests, and what reviewers look for. I was recently asked to review some code for a new JavaScript application, and thought Id like to share some of my feedback, because it covers some JavaScript fundamentals that are always useful to bear in mind.

Introduction
Reviewing code goes hand in hand with maintaining strong coding standards. That said, standards dont usually prevent logical errors or misunderstandings about the quirks of a programming language, whether its JavaScript, Ruby, Objective-C or something else. Even the most
Smashing eBook #13JavaScript Essentials 22

experienced developers can make these kinds of mistakes, and reviewing code can greatly assist with catching them. The rst reaction most of us have to criticism is to defend ourselves (or our code), and perhaps lash back. While criticism can be slightly demoralizing, think of it as a learning experience that spurs us to do better and to improve ourselves; because in many cases, once weve calmed down, it actually does. Also remember that no one is obliged to provide feedback on your work, and if the comments are indeed constructive, then be grateful for the time spent offering the input. Reviews enable us to build on the experience of others and to benet from a second pair of eyes. And at the end of the day, they are an opportunity for us to write better code. Whether we take advantage of them is entirely our choice.

Where Can I Get My Code Reviewed?


Often the most challenging part is actually nding an experienced developer who you trust to do the review. Below are some places where you can request others to review your code (sometimes in other languages, too).

Smashing eBook #13JavaScript Essentials 23

JSMentors JSMentors is a mailing list that discusses everything to do with JavaScript (including Harmony), and a number of experienced developers are on its review panel (including JD Dalton, Angus Croll and Nicholas Zakas). These mentors might not always be readily available, but they do their best to provide useful, constructive feedback on code thats been submitted. If youre looking for assistance with a specic JavaScript framework beyond vanilla JavaScript, the majority of frameworks and libraries have mailing lists or forums that you can post to and that might provide a similar level of assistance. freenode IRC Many chat rooms here are dedicated both to discussing the JavaScript language and to requests for help or review. The most popular rooms are obviously named, and #javascript is particularly useful for generic JavaScript requests, while channels such as #jquery and #dojo are better for questions and requests related to particular libraries and frameworks. Code Review (beta) You would be forgiven for confusing Code Review with StackOverow, but its actually a very useful, broad-spectrum, subjective tool for getting peer review of code. While on StackOverow you might ask the question Why isnt my code working?, Code Review is more suited to questions like Why is my code so ugly? If you still have any doubt about what it offers, I strongly recommend checking out the FAQs.

Smashing eBook #13JavaScript Essentials 24

Twitter This might sound odd, but at least half of the code that I submit for review is through social networks. Social networks work best, of course, if your code is open source, but trying them never hurts. The only thing I suggest is to ensure that the developers who you follow and interact with are experienced; a review by a developer with insufficient experience can sometimes be worse than no review at all, so be careful! GitHub + reviewth.is We all know that GitHub provides an excellent architecture for reviewing code. It comes with commits, le and line comments, update notications, an easy way to track forks of gits and repositories, and more. All thats missing is a way to actually initiate reviews. A tool called reviewth.is attempts to rectify that by giving you a post-commit hook that helps to automate this process, so changes that get posted in the wild have a clear #reviewthis hash tag, and you can tag any users who you wish to review your updates. If many of your colleagues happen to develop in the same language as you do, this set-up can work well for code reviews sourced closer to home. One workow that works well with this (if youre working on a team or on a collaborative project) is to perform your own work in a topic branch in a repository and then send through pull requests on that branch. Reviewers would examine the changes and commits and could then make line-by-line and le-by-le comments. You (the developer) would then take this feedback and do a destructive rebase on that topic branch, re-push it, and allow the review cycle to repeat until merging them would be acceptable.

How Should I Structure My Review Requests?


The following are some guidelines (based on experience) on how to structure your requests for code reviews, to increase the chances of them

Smashing eBook #13JavaScript Essentials 25

being accepted. You can be more liberal with them if the reviewer is on your team; but if the reviewer is external, then these might save you some time: Isolate what you would like to be reviewed; ensure that it can be easily run, forked and commented; be clear about where you think improvements could be made; and, above all, be patient. Make it as easy as possible for the reviewer to look at, demo and change your code. Dont submit a ZIP le of your entire website or project; very few people have the time to go through all of this. The only situation in which this would be acceptable is if your code absolutely required local testing. Instead, isolate and reduce what you would like to be reviewed on jsFiddle, on jsbin or in a GitHub gist. This will allow the reviewer to easily fork what youve provided and to show changes and comments on what can be improved. If you would prefer a diff between your work and any changes theyve recommended, you might also be interested in PasteBin, which supports this. Similarly, dont just submit a link to a page and ask them to View source in order to see what can be improved. On websites with a lot of scripts, this task would be challenging and lowers the chances of a reviewer agreeing to help. No one wants to work to nd what you want reviewed. Clearly indicate where you personally feel the implementation could be improved. This will help the reviewer quickly home in on what youre most interested in having reviewed and will save them time. Many reviewers will still look at other parts of the code youve submitted regardless, but at least help them prioritize.

Smashing eBook #13JavaScript Essentials 26

Indicate what (if any) research youve done into techniques for improving the code. The reviewer might very well suggest the same resources, but if theyre aware that you already know of them, then they might offer alternative suggestions (which is what you want). If English isnt your rst language, theres no harm in saying so. When other developers inform me of this, I know whether to keep the language in my review technical or simple. Be patient. Some reviews take several days to get back to me, and nothings wrong with that. Other developers are usually busy with other projects, and someone who agrees to schedule a look at your work is being kind. Be patient, dont spam them with reminders, and be understanding if they get delayed. Doing this sometimes pay off, because the reviewer can provide even more detailed feedback when they have more time.

What Should Code Reviews Provide?


Jonathan Betz, a former developer at Google, once said that a code review should ideally address six things: 1. Correctness Does the code do everything it claims? 2. Complexity Does it accomplish its goals in a straightforward way? 3. Consistency Does it achieve its goals consistently? 4. Maintainability Could the code be easily extended by another member of the team with a reasonable level of effort?

Smashing eBook #13JavaScript Essentials 27

5. Scalability Is the code written in such a way that it would work for both 100 users and 10,000? Is it optimized? 6. Style Does the code adhere to a particular style guide (preferably one agreed upon by the team if the project is collaborative)? While I agree with this list, expanding it into an action guide of what reviewers should practically aim to give developers would be useful. So, reviewers should do the following: Provide clear comments, demonstrate knowledge, and communicate well. Point out the shortfalls in an implementation (without being overly critical). State why a particular approach isnt recommended, and, if possible, refer to blog posts, gists, specications, MDN pages and jsPerf tests to back up the statement. Suggest alternative solutions, either in a separate runnable form or integrated in the code via a fork, so that the developer can clearly see what they did wrong. Focus on solutions rst, and style second. Suggestions on style can come later in the review, but address the fundamental problem as thoroughly as possible before paying attention to this. Review beyond the scope of what was requested. This is entirely at the reviewers discretion, but if I notice issues with other aspects of a developers implementation, then I generally try to advise them on how those, too, might be improved. Ive yet to receive a complaint about this, so I assume its not a bad thing.

Smashing eBook #13JavaScript Essentials 28

Collaborative Code Reviews


Although a review by one developer can work well, an alternative approach is to bring more people into the process. This has a few distinct advantages, including reducing the load on individual reviewers and exposing more people to your implementation, which could potentially lead to more suggestions for improvements. It also allows a reviewers comments to be screened and corrected if they happen to make a mistake. To assist the group, you may wish to employ a collaborative tool to allow all reviewers to simultaneously inspect and comment on your code. Luckily, a few decent ones out there are worth checking out: Review Board This Web-based tool is available for free under the MIT license. It integrates with Git, CVS, Mercurial, Subversion and a number of other source-control systems. Review Board can be installed on any server running Apache or lighttpd and is free for personal and commercial use. Crucible This tool by Australian software company Atlassian is also Web-based. Its aimed at the enterprise and works best with distributed teams. Crucible facilitates both live review and live commenting and, like Review Board, integrates with a number of source-control tools, including Git and Subversion. Rietveld Like the other two, Rietveld also supports collaborative review, but it was actually written by the creator of Python, Guido van Rossum. It is designed to run on Googles cloud service and benets from Guidos experience writing Mondrian, the proprietary app that Google uses internally to review its code.

Smashing eBook #13JavaScript Essentials 29

Others A number of other options for collaborative code review werent created for that purpose. These include CollabEdit (free and Webbased) and, my personal favorite, EtherPad (also free and Web-based).

(Image Source: joelogon)

Lessons From A JavaScript Code Review


On to the review. A developer recently wrote in, asking me to review their code and provide some useful suggestions on how they might improve it. While Im certainly not an expert on reviewing code (dont let the above fool you), here are the problems and solutions that I proposed. PROBLEM 1 Problem: Functions and objects are passed as arguments to other functions without any type validation. Feedback: Type validation is an essential step in ensuring that youre working only with input of a desired type. Without sanitization checks in

Smashing eBook #13JavaScript Essentials 30

place, you run the risk of users passing in just about anything (a string, a date, an array, etc.), which could easily break your application if you havent developed it defensively. For functions, you should do the following at a minimum: 1. Test to ensure that arguments being passed actually exist, 2. Do a typeof check to prevent the app from executing input that is not a valid function at all.
if (callback && typeof callback === "function"){ /* rest of your logic */ }else{ /* not a valid function */ }

Unfortunately, a simple typeof check isnt enough on its own. As Angus Croll points out in his post Fixing the typeof operator, you need to be aware of a number of issues with typeof checking if youre using them for anything other than functions. For example, typeof null returns object, which is technically incorrect. In fact, when typeof is applied to any object type that isnt a function, it returns object, not distinguishing between Array, Date, RegEx or whatever else. The solution is to use Object.prototype.toString to call the underlying internal property of JavaScript objects known as [[Class]], the class property of the object. Unfortunately, specialized built-in objects generally overwrite Object.prototype.toString, but you can force the generic toString function on them:
Object.prototype.toString.call([1,2,3]); //"[object Array]"

Smashing eBook #13JavaScript Essentials 31

You might also nd Anguss function below useful as a more reliable alternative to typeof. Try calling betterTypeOf() against objects, arrays and other types to see what happens.
function betterTypeOf( input ){ return Object.prototype.toString.call(input).match(/^\ [object\s(.*)\]$/)[1]; }

Here, parseInt() is being blindly used to parse an integer value of user input, but no base is specied. This can cause issues. In JavaScript: The Good Parts, Douglas Crockford refers to parseInt() as being dangerous. Although you probably know that passing it a string argument returns an integer, you should also ideally specify a base or radix as the second argument, otherwise it might return unexpected output. Take the following example:
parseInt('20'); parseInt('020'); parseInt('000020'); parseInt('020', 10); base to use // // // // returns returns returns returns what you expect, however 16 16 20 as we've specified the

Youd be surprised by how many developers omit the second argument, but it happens quite regularly. Remember that your users (if permitted to freely enter numeric input) wont necessarily follow standard number conventions (because theyre crazy!). Ive seen 020, ,20, ;'20 and many other variations used, so do your best to parse as broad a range of inputs as possible. The following tricks to using parseInt() are occasionally better:
Math.floor("020"); // returns 20 Math.floor("0020"); //returns 20 Number("020"); //returns 20 Number("0020"); //returns 20 +"020"; //returns 20

Smashing eBook #13JavaScript Essentials 32

PROBLEM 2 Problem: Checks for browser-specic conditions being met are repeated throughout the code base (for example, feature detection, checks for supported ES5 features, etc.). Feedback: Ideally, your code base should be as DRY as possible, and there are some elegant solutions to this problem. For example, you might benet from the load-time conguration pattern here (also called load-time and init-time branching). The basic idea is that you test a condition only once (when the application loads) and then access the result of that test for all subsequent checks. This pattern is commonly found in JavaScript libraries that congure themselves at load time to be optimized for a particular browser. This pattern could be implemented as follows:
var tools = { addMethod: null, removeMethod: null }; if(/* condition for native support */){ tools.addMethod = function(/* params */){ /* method logic */ } }else{ /* fallback - eg. for IE */ tools.addMethod = function(/* */){ /* method logic */ } }

The example below demonstrates how this can be used to normalize getting an XMLHttpRequest object.
var utils = { getXHR: null };
Smashing eBook #13JavaScript Essentials 33

if(window.XMLHttpRequest){ utils.getXHR = function(){ return new XMLHttpRequest; } }else if(window.ActiveXObject){ utils.getXHR = function(){ /* this has been simplified for example sakes */ return new ActiveXObject(Microsoft.XMLHTTP); } }

For a great example, Stoyan Stefanov applies this to attaching and removing event listeners cross-browser, in his book JavaScript Patterns:
var utils = { addListener: null, removeListener: null }; // the implementation if (typeof window.addEventListener === function) { utils.addListener = function ( el, type, fn ) { el.addEventListener(type, fn, false); }; utils.removeListener = function ( el, type, fn ) { el.removeEventListener(type, fn, false); }; } else if (typeof document.attachEvent === function) { // IE utils.addListener = function ( el, type, fn ) { el.attachEvent(on + type, fn); }; utils.removeListener = function ( el, type, fn ) { el.detachEvent(on + type, fn); }; } else { // older browsers utils.addListener = function ( el, type, fn ) { el[on + type] = fn; }; utils.removeListener = function ( el, type, fn ) { el[on + type] = null;

Smashing eBook #13JavaScript Essentials 34

}; }

PROBLEM 3 Problem: The native Object.prototype is being extended regularly. Feedback: Extending native types is generally frowned upon, and few (if any) popular code bases should dare to extend Object.prototype. The reality is that there is not likely a situation in which you absolutely need to extend it in this way. In addition to breaking the object-as-hash tables in JavaScript and increasing the chance of naming collisions, its generally considered bad practice, and modifying it should only be a last resort (this is quite different from extending your own custom object properties). If for some reason you do end up extending the object prototype, ensure that the method doesnt already exist, and document it so that the rest of the team is aware why its necessary. You can use the following code sample as a guide:
if(typeof Object.prototype.myMethod != function){ Object.prototype.myMethod = function(){ //implem }; }

Juriy Zaytsev has a great post on extending native and host objects, which may be of interest. PROBLEM 4 Problem: Some of the code is heavily blocking the page because its either waiting on processes to complete or data to load before executing anything further.

Smashing eBook #13JavaScript Essentials 35

Feedback: Page-blocking makes for a poor user experience, and there are a number of ways to work around it without impairing the application. One solution is to use deferred execution (via promises and futures). The basic idea with promises is that, rather than issuing blocking calls for resources, you immediately return a promise for a future value that will eventually be fullled. This rather easily allows you to write non-blocking logic that can be run asynchronously. It is common to introduce callbacks into this equation that execute once the request completes. Ive written a relatively comprehensive post on this with Julian Aubourg, if youre interested in doing this through jQuery, but it can of course be implemented with vanilla JavaScript as well. Micro-framework Q offers a CommonJS-compatible implementation of promises and futures that is relatively comprehensive and can be used as follows:

Smashing eBook #13JavaScript Essentials 36

/* define a promise-only delay function that resolves when a timeout completes */ function delay(ms) { var deferred = Q.defer(); setTimeout(deferred.resolve, ms); return deferred.promise; } /* usage of Q with the 'when' pattern to execute a callback once delay fulfils the promise */ Q.when(delay(500), function () { /* do stuff in the callback */ });

If youre looking for something more basic that can be read through, then here is Douglas Crockfords implementation of promises:
function make_promise() { var status = unresolved, outcome, waiting = [], dreading = []; function vouch( deed, func ) { switch (status) { case unresolved: (deed === fulfilled ? waiting : dreading).push(func); break; case deed: func(outcome); break; } }; function resolve( deed, value ) { if (status !== unresolved) { throw new Error(The promise has already been resolved: + status); } status = deed;

Smashing eBook #13JavaScript Essentials 37

outcome = value; (deed == fulfilled ? waiting : dreading).forEach(function (func) { try { func(outcome); } catch (ignore) {} }); waiting = null; dreading = null; }; return { when: function ( func ) { vouch(fulfilled, func); }, fail: function ( func ) { vouch(smashed, func); }, fulfill: function ( value ) { resolve(fulfilled, value); }, smash: function ( string ) { resolve(smashed, string); }, status: function () { return status; } }; };

PROBLEM 5 Problem: Youre testing for explicit numeric equality of a property using the == operator, but you should probably be using === instead Feedback: As you may or may not know, the identity == operator in JavaScript is fairly liberal and considers values to be equal even if theyre of completely different types. This is due to the operator forcing a coercion of

Smashing eBook #13JavaScript Essentials 38

values into a single type (usually a number) prior to performing any comparison. The === operator will, however, not do this conversion, so if the two values being compared are not of the same type, then === will just return false. The reason I recommend considering === for more specic type comparison (in this case) is that == is known to have a number of gotchas and is considered to be unreliable by many developers. You might also be interested to know that in abstractions of the language, such as CoffeeScript, the == operator is completely dropped in favor of === beneath the hood due to the formers unreliability. Rather than take my word for it, see the examples below of boolean checks for equality using ==, some of which result in rather unexpected outputs.

Smashing eBook #13JavaScript Essentials 39

3 == "3" // true 3 == "03" // true 3 == "0003" // true 3 == "+3" //true 3 == [3] //true 3 == (true+2) //true \t\r\n == 0 //true "\t\r\n" == 0 //true "\t" == 0 // true "\t\n" == 0 // true "\t\r" == 0 // true " " == 0 // true " \t" == 0 // true " \ " == 0 // true " \r\n\ " == 0 //true

The reason that many of the (stranger) results in this list evaluate to true is because JavaScript is a weakly typed language: it applies type coercion wherever possible. If youre interested in learning more about why some of the expressions above evaluate to true, look at the Annotated ES5 guide, whose explanations are rather fascinating. Back to the review. If youre 100% certain that the values being compared cannot be interfered with by the user, then proceed with using the == operator with caution. Just remember that === covers your bases better in the event of an unexpected input. PROBLEM 6 Problem: An uncached array length is being used in all for loops. This is particularly bad because youre using it when iterating through an HTMLCollection. Heres an example:

Smashing eBook #13JavaScript Essentials 40

for( var i=0; i<myArray.length;i++ ){ /* do stuff */ }

Feedback: The problem with this approach (which I still see a number of developers using) is that the array length is unnecessarily re-accessed on each loops iteration. This can be very slow, especially when working with HTMLCollections (in which case, caching the length can be anywhere up to 190 times faster than repeatedly accessing it, as Nicholas C. Zakas mentions in his book High-Performance JavaScript). Below are some options for caching the array length.
/* cached outside loop */ var len = myArray.length; for ( var i = 0; i < len; i++ ) { } /* cached inside loop */ for ( var i = 0, len = myArray.length; i < len; i++ ) { } /* cached outside loop using while */ var len = myArray.length; while (len--) { }

A jsPerf test that compares the performance benets of caching the array length inside and outside the loop, using prex increments, counting down and more is also available, if you would like to study which performs the best. PROBLEM 7 Problem: jQuerys $.each() is being used to iterate over objects and arrays, in some cases while for is being used in others.
Smashing eBook #13JavaScript Essentials 41

Feedback: In jQuery, we have two ways to seamlessly iterate over objects and arrays. The generic $.each iterates over both of these types, whereas $.fn.each() iterates over a jQuery object specically (where standard objects can be wrapped with $() should you wish to use them with the latter). While the lower-level $.each performs better than $.fn.each(), both standard JavaScript for and while loops perform much better than either, as proven by this jsPerf test. Below are some examples of loop alternatives that also perform better:
/* jQuery $.each */ $.each(a, function() { e = $(this); }); /* classic for loop */ var len = a.length; for ( var i = 0; i < len; i++ ) { //if this must be a jQuery object do.. e = $(a[i]); //otherwise just e = a[i] should suffice }; /* reverse for loop */ for ( var i = a.length; i-- ) { e = $(a[i]); } /* classic while loop */ var i = a.length; while (i--) { e = $(a[i]); } /* alternative while loop */ var i = a.length - 1; while ( e = a[i--] ) { $(e) };

Smashing eBook #13JavaScript Essentials 42

You might nd Angus Crolls post on Rethinking JavaScript for Loops an interesting extension to these suggestions. Given that this is a data-centric application with a potentially large quantity of data in each object or array, you should consider a refactor to use one of these. From a scalability perspective, you want to shave off as many milliseconds as possible from process-heavy routines, because these can build up when hundreds or thousands of elements are on the page. PROBLEM 8 Problem: JSON strings are being built in-memory using string concatenation. Feedback: This could be approached in more optimal ways. For example, why not use JSON.stringify(), a method that accepts a JavaScript object and returns its JSON equivalent. Objects can generally be as complex or as deeply nested as you wish, and this will almost certainly result in a simpler, shorter solution.
var myData = {}; myData.dataA = [a, b, c, d]; myData.dataB = { animal: cat, color: brown }; myData.dataC = { vehicles: [{ type: ford, tint: silver, year: 2015 }, { type: honda, tint: black, year: 2012 }] };

Smashing eBook #13JavaScript Essentials 43

myData.dataD = { buildings: [{ houses: [{ streetName: sycamore close, number: 252 }, { streetName: slimdon close, number: 101 }] }] }; console.log(myData); //object var jsonData = JSON.stringify(myData); console.log(jsonData); /* {"dataA":["a","b","c","d"],"dataB": {"animal":"cat","color":"brown"},"dataC":{"vehicles": [{"type":"ford","tint":"silver","year":"2015"}, {"type":"honda","tint":"black","year":"2012"}]},"dataD": {"buildings":[{"houses":[{"streetName":"sycamore close","number":"252"},{"streetName":"slimdon close","number":"101"}]}]}} */

As an extra debugging tip, if you would like to pretty-print JSON in your console for easier reading, then the following extra arguments to stringify() will achieve this:
JSON.stringify({ foo: "hello", bar: "world" }, null, 4);

PROBLEM 9 Problem: The namespacing pattern used is technically invalid. Feedback: While namespacing is implemented correctly across the rest of the application, the initial check for namespace existence is invalid. Heres what you currently have:

Smashing eBook #13JavaScript Essentials 44

if ( !MyNamespace ) { MyNamespace = { }; }

The problem is that !MyNamespace will throw a ReferenceError, because the MyNamespace variable was never declared. A better pattern would take advantage of boolean conversion with an inner variable declaration, as follows:
if ( !MyNamespace ) { var MyNamespace = { }; }

//or var myNamespace = myNamespace || {}; // Although a more efficient way of doing this is: // myNamespace || ( myNamespace = {} ); // jsPerf test: http://jsperf.com/conditional-assignment //or if ( typeof MyNamespace == undefined ) { var MyNamespace = { }; }

This could, of course, be done in numerous other ways. If youre interested in reading about more namespacing patterns (as well as some ideas on namespace extension), I recently wrote Essential JavaScript Namespacing Patterns. Juriy Zaytsev also has a pretty comprehensive post on namespacing patterns.

Conclusion
Thats it. Reviewing code is a great way to enforce and maintain quality, correctness and consistency in coding standards at as high a level as possible. I strongly recommend that all developers give them a try in their daily projects, because theyre an excellent learning tool for both the

Smashing eBook #13JavaScript Essentials 45

developer and the reviewer. Until next time, try getting your code reviewed, and good luck with the rest of your project!

Smashing eBook #13JavaScript Essentials 46

Find

e Right JavaScript Solution With

A 7-Step Test
Christian Heilmann
As Web developers and designers, we are spoilt for choice right now. To build a complex Web application or even just spice up a website with some highly interactive interface element, we have hundreds of pre-built solutions to choose from. Every library comes with widgets and solutions, and every developer tries to make a name for him or herself by releasing a funky JavaScript solution to a certain interface problem. We can pick from dozens of menus, image carousels, tabs, form validators and lightboxes. Having this much choice makes it easy for us to pick and choose, which is where things go wrong. In most cases, we measure the quality of a solution by its convenience to us. Our main reasons for picking one solution over another are: Does it do what I need it to do? Does it look cool? Does it sound easy to use? Would I want to use it? Does it use the framework Im committed to? The things you should really look for are different, though: How stable is the solution? Is a good alternative available if this one doesnt work?

Smashing eBook #13JavaScript Essentials 47

How easy is it to customize? Do you need to be a JavaScript expert to modify the widget? How usable and accessible is it? Are users who dont have a mouse or are on a mobile browser blocked? Do you understand whats going on? Would you be able to x a problem and explain it to others? Is it a contained solution? Will other scripts be able to interfere with it, or would it contaminate the document? How dedicated is the developer? Will the solution be maintained in the future? What is supported, and how can you extend functionality? A new browser and client request is always around the corner?In this article, well show some ways to nd out more about these issues. First of all, though, understanding what it means to develop for the Web is important.

Its Not About You


Most of the reasons why we choose a particular solution right away are very much about us, and this is where we tread on thin ice. We dont consume what we put on the Web; rather, people we dont know do, and we cant make assumptions about their ability, set-up, technical understanding or taste. We wont make our product a success; we only build it, and thus we are the worst testers of it possible. Ive been developing for the Web professionally for over 10 years now, working on everything from personal blogs to multi-language enterprise CMS solutions to complex Web applications, and Ive learnt one thing on the journey: never build for yourself or the client. Instead, build for the people

Smashing eBook #13JavaScript Essentials 48

who will use the product and the poor person who has to take over the project when you leave. Much as we have to act now to minimize our massive carbon footprint, we need to leave a cleaner Web behind. To keep the Web a thriving market and sustainable work environment, we have to change the way we work in it and leave behind unmaintainable, bloated and semi-workable, albeit pretty, solutions. We have to make it easier for people to use Web applications and save other developers from wasting hours trying to understand what we did when they are asked to change or extend it at a later stage.

Introducing

e 7-Step Test For JavaScript Widgets

To this end, Ive put together a seven-step test to apply to any out-of-thebox widget you nd. All of the recommendations have a rationale, so please ponder it before dismissing the arguments as elitist or not really suitable to our environment. Lets not forget that even when something is free, its developer will try to sell it to you for the fame, and many a solution is defended tooth and nail on mailing lists instead of being changed or updated. The reason is that, as developers we are always on the move. Maintaining and extending an old solution is not as sexy as creating a cool new one. This leads to ruins that once enjoyed love when they were state of the art but now rust away on the Internet. To kick the tires of any out-of-the box solution, I mostly use one tool: the Firefox Web developer toolbar. It is available on the Firefox Add-On website and gives you an easy way to test whats happening in your widget of choice. Okay, here goes: seven things to test when deciding on a JavaScript solution.

Smashing eBook #13JavaScript Essentials 49

1. What Happens If JavaScript Is Turned O?


The rst test I do with any widget is turn off JavaScript not after the document has loaded but before. Turning off JavaScript with the Web developer toolbar is very easy. Simply select Disable All JavaScript from the Disable menu and reload the page:

The rationale is that there are a lot of reasons why JavaScript may not be used: company proxies or personal rewalls could lter it out, other scripts could create errors and mess with yours, or the system in use could simply not have JavaScript enabled. Think of mobile environments, for example. You dont need full functionality when JavaScript is not available, just a working interface that doesnt overload users and interactive elements that

Smashing eBook #13JavaScript Essentials 50

work. If a button does nothing when users activate it, those users will stop trusting you; after all, you havent kept your promises. Overloading is another issue. A lot of widgets use CSS and JavaScript to squeeze a lot of content into a very small space: think tabbed content elements and image carousels. What should be their fallback? If you turn off JavaScript and have 50 pictures where you planned for 2, then that would be a good user experience. A better fallback would be a server-side solution for the same functionality or to show the rst 2 and then offer a link to a gallery page with the remaining pictures. Sometimes the JavaScript for a particular widget is actually very good but the demo websites have been done badly. Hiding elements with CSS and then revealing them with JavaScript, for example, is very common. But if JavaScript is turned off, the solution will break. Good demos and solutions use JavaScript to add a class to the body of the document and make all of the CSS dependent on that class. The trick that any good JavaScript widget should do is to make any functionality depend on JavaScript by using JavaScript; that way, you never have any functionality that wont work. This technique is called unobtrusive JavaScript, and I have written a course on it and set a few rules for it a while back.

2. How To Change

e Look, Feel And Content?

A widget whose look and feel are hard-coded is a pain to maintain. You cannot expect future designers to know how to change a certain color by hunting through your JavaScript les. This is how we end up with bloated CSS les, because people add random IDs and classes to enhance the specicity of their CSS selectors. Good widgets have their look and feel contained in a CSS le and give you handles (i.e. dynamically applied classes) to apply your own styling. If you
Smashing eBook #13JavaScript Essentials 51

nd yourself having to change JavaScript to change the look and feel, alarm bells should go off in your head. This gets worse if you have content such as text labels in the JavaScript or if only a xed number of elements can be displayed (as in the case of navigation menus). Labels and number of elements are what change the most in any Web product. For starters, you will probably roll out your product across different markets and will have to translate the buttons and menus. Good gadgets have conguration objects that allow you to change the number of elements and dene the text labels without having to change the main JavaScript. The reason for this is that the functional part of the widget should be separated from the maintainer. If the widget has a security or performance problem, you should be able to replace it without losing your conguration and localization work. Otherwise people would be very likely to keep insecure code on the Web, which is one of the reasons why our inboxes are full of spam.

3. How Usable And Semantic Is

e Final Product?

A lot of widget creators are very happy to announce that their products are Web-standards compliant and accessible because of it. While Webstandards compliance is important, it does not indicate the quality or usefulness of the product. One cannot really validate semantics with an automated tool. For example, the following examples are both valid HTML:
<div class="menu"> <div class="section"> <span class="label">Animals</span> <div class="subsection"> <div class="item">Giraffe</div> <div class="item">Donkey</div> <div class="item">Cheetah</div>

Smashing eBook #13JavaScript Essentials 52

<div class="item">Hippo</div> </div> </div> <div class="section"> <span class="label">Stones</span> <div class="subsection"> <div class="item">Diamond</div> <div class="item">Ruby</div> <div class="item">Onyx</div> </div> </div> </div> <ul class="menu"> <li><button>Animals</button> <ul> <li><a href="giraffe.html">Giraffe</a></li> <li><a href="donkey.html">Donkey</a></li> <li><a href="cheetah.html">Cheetah</a></li> <li><a href="hippo.html">Hippo</a></li> </ul> </li> <li><button>Stones</button> <ul> <li><a href="diamond.html">Diamond</a></li> <li><a href="ruby.html">Ruby</a></li> <li><a href="onyx.html">Onyx</a></li> </ul> </li> </ul>

The second example works without JavaScript and uses much less HTML. It also requires much less CSS for styling because you would simply take advantage of the cascade. Furthermore, the HTML on which the widget is based is only half the story. What the JavaScript generates also needs to be valid, usable and

Smashing eBook #13JavaScript Essentials 53

accessible, and you can check this when you check the generated source in the Web developer toolbar. To do this, right-click anywhere in the document and select Web Developer View Source View Generated Source:

Usability and accessibility (accessibility being, in essence, merely a more comprehensive understanding of usability) are harder to test. But one very good test is to check how keyboard-accessible a widget it. Keyboard-only users are on the rise, and widgets that work only with mouse-over events would not usable on a touchscreen mobile, for instance. Many widgets provide basic keyboard access (e.g. using the Tab key to jump from one link to another, and the Enter key to activate each), but this is not proper accessibility. A menu, for example, should not be navigated by tabbing through each of the items because this would require far too many keystrokes. Instead, the user should be able to tab to the main menu bar and from there use the cursor keys to navigate. A modal pop-up (commonly called a lightbox) should be able to be closed with a keyboard by hitting the Escape key or by tabbing to the Close
Smashing eBook #13JavaScript Essentials 54

button. If it is a multi-item lightbox, you should also be able to navigate the items with the cursor keys. The W3Cs WAI websites have some great examples of how widgets should react to keyboard use, and Todd Kloots of Yahoo does a great job of explaining the techniques behind good keyboard usability (also as a video and using YUI3 and focusing on WAI-ARIA). Patrick Lauke of Opera also wrote a great article on the subject and gave a presentation at last years Future of Web Design. If you are a Mac user, make sure to turn on keyboard access before declaring a widget faulty. People also need to be able to resize the text in their browser. So test the widgets at several text sizes. Using Internet Explorer 6 for this is important because it is the main culprit in font-resizing issues. Newer browsers do a much better job of zooming the entire interface, but you cannot expect end users to know how to use them.

4. Do You Understand Whats Going On?


If youve read the Harry Potter books (or even seen the movies), you know that you shouldnt trust magic without knowing what is going on. A book that responds to your writing is as suspicious as a widget that does something so amazing that you have no clue how it happened. Remember, if the doo-dad stops working, you will be asked to x it or explain what went wrong. Therefore, it is important to at least know the basics of what JavaScript spell was cast to transform a list of images into an all-singing, all-dancing carousel. Good widgets have technical documentation for that kind of thing, and some even re off custom events that tell you when something is happening. That way, you can debug the tool by waiting for these events and analyzing the current state of play. It also allows you to extend functionality, which well come back to in step #7.
Smashing eBook #13JavaScript Essentials 55

5. Does It Play Well With Others?


The biggest problem with any JavaScript on the Web right now is that its security model gives every script on the page the same rights. This means that one bad script can mess up the users whole experience because it may override parts of another script. The places where scripts can clash are in variable and function names and events. If your widget does not protect its variables and function names or if it applies event functionality to elements without checking that other scripts are doing the same, youll have a problem. Say you have an element with the ID menu, and you have one script that turns its HTML content into a drop-down menu and another that enhances the different links by showing a beautiful roll-over message. If neither of these scripts append to the existing functionality and just apply it, youll have either a beautiful roll-over or a menu, depending on which script is applied last. The good news is that for widgets that are based on libraries, this event clash is very unlikely because libraries work around that out of the box. You can test for the problem of function and variable names that can be overwritten by other scripts. JSLint is a tool and website where you can check JavaScript for syntactical problems such as unprotected variables. It is a very strict tool, though, and not all of its warnings are actually dealbreakers. But testing with JSLint is the hallmark of a professional Web developer. You do want your code to play well with others.

6. How Dedicated Is

e Maintainer?

When choosing a widget, you want to be very sure that the maintainer is dedicated to keeping it up to date and to xing the script for future browsers and environments. This is rarely the case, and a lot of software is released
Smashing eBook #13JavaScript Essentials 56

with an as is statement, absolving the creator of any liability for problems it may cause now or in the future. Software, especially the kind that is executed in the browser and for Web consumption, has to constantly evolve. Things that were once state of the art might be clumsy now. Some software turned out to perform poorly or be outright security holes. Whenever people claim that we have a great baseline environment on the Web for screen space and processing power, something comes along that debunks it. Right now, testing on dual or quad-core processors with resolutions starting at 1280 might be normal for us designers, but given the sales gures of smartphones and netbooks, planning for audiences other than these high-end ones might be a good idea. For developers, maintenance is the most boring task. When we release awesome widgets to the world, we dont want to think about that phase of software delivery. Granted, most widgets are released as open source, but sadly, not many developers x or improve on other peoples work; building and releasing something almost identical but slightly modied is much more fun. As the user of someone elses widget, you dont want this to y back in your face, so you need to see just how dedicated the developer is. A few questions to ask are: Is there a simple way to report bugs? Is there trail of improvements and bug xes? Is there a history of comments and changes to the widget based on that feedback? Has the widget been used in real scenarios, large projects or implementations similar to yours? What were the experiences of those who used it?

Smashing eBook #13JavaScript Essentials 57

Does the solution have a community (i.e. are there a few people on mailing lists or in forums helping each other out, rather than overloading the original developer)? If the developer has no big personal stake in the widget or there is no group of developers or commercial users, then there is a high chance that you will see few or no xes or improvements in future, and you will be responsible for supporting the next browser version that behaves badly.

7. Is

ere A Testing Plan, And Is Upgrading And

Extending Easy?
One last thing to consider is what will happen in future. Claims that the widget will work in every environment are bogus because that cannot be done. The great power of the Web is that software solutions can adapt to the environment they are being used in. If you use Netscape 4, you should see a few images; if you use the newest Webkit browser, you should see a fancy image carousel with animation and fading; that sort of thing. A good widget will have a proven test report covering which browsers and environments it has been tested in and what the known issues are. There will always be issues, and claiming otherwise is arrogant or ignorant. Upgrading your widget should be easy and painless, and there should be some versioning in place, with new versions being backwards-compatible. Extending the widget should be easy. We spoke earlier about not being limited to a particular number of items or a certain look and feel. But if you really use a widget, you will nd you have to override certain functionality and react to various changes. Good widgets either have an API (a programming interface to extend it) or re custom events for you to listen to. Custom events are interesting moments in a users interaction with the widget. For example, a button will tell the script when you have activated it,
Smashing eBook #13JavaScript Essentials 58

and if you write the widget a certain way, you can tell the world (or in this case, other scripts) when something happens to it. You can notify that a container has been opened, that data has returned from the Web or that a menu was too large to be displayed to the right and had to be moved to the left. Widgets built with the Yahoo User Interface library, for example, come with a lot of custom events:

This allows you to monitor what is going on (like for debugging purposes) and extend functionality. The demo page for the AutoComplete control, for

Smashing eBook #13JavaScript Essentials 59

example, displays in a logging console on the right what happens under the hood when you use the auto-complete eld.

By subscribing to these events in JavaScript, overriding the original functionality for something new is pretty easy; in this case, we have an autocomplete that returns photos and allows you to collect them.

Smashing eBook #13JavaScript Essentials 60

Custom events are a great way to extend a widget while keeping the core code easy to upgrade.

One Final Word On Size


One last thing to mention: some widget developers use a certain argument to advocate for their solution but which is totally irrelevant to your decision, and that is size. Advertising-speak like A drop-down menu in 20 lines of JavaScript or A full featured lightbox in under 2 KB is fun and good for the developers ego, but in reality it is no measure of the quality of the solution. While you should avoid JavaScript solutions that are massive (lets say 100 KB), code that has been written to be very generic and easy to extend will always be bigger than code that has been written to serve a single purpose. Any widget whose size is proudly trumpeted and is meant to be used by people who are not as good at developing as the initial owner will get bigger over time
Smashing eBook #13JavaScript Essentials 61

anyway. Developers like to play the numbers game, but maintainable code is different than extreme number-crunching. And if you get your kicks from this sort of thing, try the demo scene in which Farbrausch proved with The Product in 2000 that you can t a seven-minute animation with music and synthesized voices into 64 KB.am

Smashing eBook #13JavaScript Essentials 62

Ten Oddities And Secrets About JavaScript


Andy Croxall
JavaScript. At once bizarre and yet beautiful, it is surely the programming language that Pablo Picasso would have invented. Null is apparently an object, an empty array is apparently equal to false, and functions are bandied around as though they were tennis balls. This article is aimed at intermediate developers who are curious about more advanced JavaScript. It is a collection of JavaScripts oddities and well-kept secrets. Some sections will hopefully give you insight into how these curiosities can be useful to your code, while other sections are pure WTF material. So, lets get started.

Data Types And Denitions


1. NULL IS AN OBJECT Lets start with everyones favorite JavaScript oddity, as well known as it is. Null is apparently an object, which, as far as contradictions go, is right up there with the best of them. Null? An object? Surely, the denition of null is the total absence of meaningful value, you say. Youd be right. But thats the way it is. Heres the proof:
alert(typeof null); //alerts 'object'

Despite this, null is not considered an instance of an object. (In case you didnt know, values in JavaScript are instances of base objects. So, every

Smashing eBook #13JavaScript Essentials 63

number is an instance of the Number object, every object is an instance of the Object object, and so on.) This brings us back to sanity, because if null is the absence of value, then it obviously cant be an instance of anything. Hence, the following evaluates to false:
alert(null instanceof Object); //evaluates false

2. NAN IS A NUMBER You thought null being an object was ridiculous? Try dealing with the idea of NaN !not a number!!being a number! Moreover, NaN is not considered equal to itself! Does your head hurt yet?
alert(typeof NaN); //alerts 'Number' alert(NaN === NaN); //evaluates false

In fact NaN is not equal to anything. The only way to conrm that something is NaN is via the function isNaN(). 3. AN ARRAY WITH NO KEYS == FALSE (ABOUT TRUTHY AND FALSY) Heres another much-loved JavaScript oddity:
alert(new Array() == false); //evaluates true

To understand whats happening here, you need to understand the concepts of truthy and falsy. These are sort of true/false-lite, which will anger you somewhat if you majored in logic or philosophy. Ive read many explanations of what truthy and falsy are, and I feel the easiest one to understand is this: in JavaScript, every non-boolean value has a built-in boolean ag that is called on when the value is asked to behave like a boolean; like, for example, when you compare it to a boolean. Because apples cannot be compared to pears, when JavaScript is asked to compare values of differing data types, it rst coerces them into a common

Smashing eBook #13JavaScript Essentials 64

data type. False, zero, null, undefined, empty strings and NaN all end up becoming false !not permanently, just for the given expression. An example to the rescue:
var someVar = 0; alert(someVar == false); //evaluates true

Here, were attempting to compare the number 0 to the boolean false. Because these data types are incompatible, JavaScript secretly coerces our variable into its truthy or falsy equivalent, which in the case of 0 (as I said above) is falsy. You may have noticed that I didnt include empty arrays in the list of falsies above. Empty arrays are curious things: they actually evaluate to truthy but, when compared against a boolean, behave like a falsy. Confused yet? With good cause. Another example perhaps?
var someVar = []; //empty array alert(someVar == false); //evaluates true if (someVar) alert('hello'); //alert runs, so someVar evaluates to true

To avoid coercion, you can use the value and type comparison operator, ===, (as opposed to ==, which compares only by value). So:
var someVar = alert(someVar alert(someVar number, not a

0; == false); //evaluates true zero is a falsy === false); //evaluates false zero is a boolean

Phew. As youve probably gathered, this is a broad topic, and I recommend reading up more on it!!particularly on data coercion, which, while not uniquely a JavaScript concept, is nonetheless prominent in JavaScript. I discuss the concept of truthy and falsy and data coercion more over here. And if you really want to sink your teeth into what happens internally when JavaScript is asked to compare two values, then check out section 11.9.3 of the ECMA-262 document specication.
Smashing eBook #13JavaScript Essentials 65

Regular Expressions
4. REPLACE() CAN ACCEPT A CALLBACK FUNCTION This is one of JavaScripts best-kept secrets and arrived in v1.3. Most usages of replace() look something like this:
alert('10 13 21 48 52'.replace(/d+/g, '*')); //replace all numbers with *

This is a simple replacement: a string, an asterisk. But what if we wanted more control over how and when our replacements take place? What if we wanted to replace only numbers under 30? This cant be achieved with regular expressions alone (theyre all about strings, after all, not maths). We need to jump into a callback function to evaluate each match.
alert('10 13 21 48 52'.replace(/d+/g, function(match) { return parseInt(match) < 30 ? '*' : match; }));

For every match made, JavaScript calls our function, passing the match into our match argument. Then, we return either the asterisk (if the number matched is under 30) or the match itself (i.e. no match should take place). 5. REGULAR EXPRESSIONS: MORE THAN JUST MATCH AND REPLACE Many intermediate JavaScript developers get by just on match and replace with regular expressions. But JavaScript denes more methods than these two. Of particular interest is test(), which works like match except that it doesnt return matches: it simply conrms whether a pattern matches. In this sense, it is computationally lighter.
alert(/w{3,}/.test('Hello')); //alerts 'true'

Smashing eBook #13JavaScript Essentials 66

The above looks for a pattern of three or more alphanumeric characters, and because the string Hello meets that requirement, we get true. We dont get the actual match, just the result. Also of note is the RegExp object, by which you can create dynamic regular expressions, as opposed to static ones. The majority of regular expressions are declared using short form (i.e. enclosed in forward slashes, as we did above). That way, though, you cant reference variables, so making dynamic patterns is impossible. With RegExp(), though, you can.
function findWord(word, string) { var instancesOfWord = string.match(new RegExp('\b'+word +'\b', 'ig')); alert(instancesOfWord); } findWord('car', 'Carl went to buy a car but had forgotten his credit card.');

Here, were making a dynamic pattern based on the value of the argument word. The function returns the number of times that word appears in string as a word in its own right (i.e. not as a part of other words). So, our example returns car once, ignoring the car tokens in the words Carl and card. It forces this by checking for a word boundary (b) on either side of the word that were looking for. Because RegExp are specied as strings, not via forward-slash syntax, we can use variables in building the pattern. This also means, however, that we must double-escape any special characters, as we did with our word boundary character.

Smashing eBook #13JavaScript Essentials 67

Functions And Scope


6. YOU CAN FAKE SCOPE The scope in which something executes denes what variables are accessible. Free-standing JavaScript (i.e. JavaScript that does not run inside a function) operates within the global scope of the window object, to which everything has access; whereas local variables declared inside functions are accessible only within that function, not outside.
var animal = 'dog'; function getAnimal(adjective) { alert(adjective+' '+this.animal); } getAnimal('lovely'); //alerts 'lovely dog';

Here, our variable and function are both declared in the global scope (i.e. on window). Because this always points to the current scope, in this example it points to window. Therefore, the function looks for window.animal, which it nds. So far, so normal. But we can actually con our function into thinking that its running in a different scope, regardless of its own natural scope. We do this by calling its built-in call() method, rather than the function itself:
var animal = 'dog'; function getAnimal(adjective) { alert(adjective+' '+this.animal); }; var myObj = {animal: 'camel'}; getAnimal.call(myObj, 'lovely'); //alerts 'lovely camel'

Here, our function runs not on window but on myObj !specied as the rst argument of the call method. Essentially, call() pretends that our function is a method of myObj (if this doesnt make sense, you might want to read up on JavaScripts system of prototypal inheritance). Note also that any arguments we pass to call() after the rst will be passed on to our function!!hence were passing in lovely as our adjective argument.

Smashing eBook #13JavaScript Essentials 68

Ive heard JavaScript developers say that theyve gone years without ever needing to use this, not least because good code design ensures that you dont need this smoke and mirrors. Nonetheless, its certainly an interesting one. As an aside, apply() does the same job as call(), except that arguments to the function are specied as an array, rather than as individual arguments. So, the above example using apply() would look like this:
getAnimal.apply(myObj, ['lovely']); //func args sent as array

7. FUNCTIONS CAN EXECUTE THEMSELVES Theres no denying it:


(function() { alert('hello'); })(); //alerts 'hello'

The syntax is simple enough: we declare a function and immediately call it just as we call other functions, with () syntax. You might wonder why we would do this. It seems like a contradiction in terms: a function normally contains code that we want to execute later, not now, otherwise we wouldnt have put the code in a function. One good use of self-executing functions (SEFs) is to bind the current values of variables for use inside delayed code, such as callbacks to events, timeouts and intervals. Here is the problem:
var someVar = 'hello'; setTimeout(function() { alert(someVar); }, 1000); var someVar = 'goodbye';

Newbies in forums invariably ask why the alert in the timeout says goodbye and not hello. The answer is that the timeout callback function is precisely that!!a callback!!so it doesnt evaluate the value of someVar until it runs. And by then, someVar has long since been overwritten by goodbye.

Smashing eBook #13JavaScript Essentials 69

SEFs provide a solution to this problem. Instead of specifying the timeout callback implicitly as we do above, we return it from an SEF, into which we pass the current value of someVar as arguments. Effectively, this means we pass in and isolate the current value of someVar, protecting it from whatever happens to the actual variable someVar thereafter. This is like taking a photo of a car before you respray it; the photo will not update with the resprayed color; it will forever show the color of the car at the time the photo was taken.
var someVar = 'hello'; setTimeout((function(someVar) { return function() { alert(someVar); } })(someVar), 1000); var someVar = 'goodbye';

This time, it alerts hello, as desired, because it is alerting the isolated version of someVar (i.e. the function argument, not the outer variable).

e Browser
8. FIREFOX READS AND RETURNS COLORS IN RGB, NOT HEX Ive never really understood why Mozilla does this. Surely it realizes that anyone interrogating computed colors via JavaScript is interested in hex format and not RGB. To clarify, heres an example:
<!-#somePara { color: #f90; } --> Hello, world! <script> var ie = navigator.appVersion.indexOf('MSIE') != -1; var p = document.getElementById('somePara');

Smashing eBook #13JavaScript Essentials 70

alert(ie ? p.currentStyle.color : getComputedStyle(p, null).color); </script>

While most browsers will alert ff9900, Firefox returns rgb(255, 153, 0), the RGB equivalent. Plenty of JavaScript functions are out there for converting RGB to hex. Note that when I say computed color, Im referring to the current color, regardless of how it is applied to the element. Compare this to style, which reads only style properties that were implicitly set in an elements style attribute. Also, as youll have noticed in the example above, IE has a different method of detecting computed styles from other browsers. As an aside, jQuerys css() method encompasses this sort of computed detection, and it returns styles however they were applied to an element: implicitly or through inheritance or whatever. Therefore, you would relatively rarely need the native getComputedStyle and currentStyle.

Miscellaneous
9. 0.1 + 0.2 !== 0.3 This one is an oddity not just in JavaScript; its actually a prevailing problem in computer science, and it affects many languages. The output of this is 0.30000000000000004. This has to do with an issue called machine precision. When JavaScript tries to execute the line above, it converts the values to their binary equivalents. This is where the problem starts. 0.1 is not really 0.1 but rather its binary equivalent, which is a near-ish (but not identical) value. In essence, as soon as you write the values, they are doomed to lose their precision. You might have just wanted two simple decimals, but what you get, as Chris Pine

Smashing eBook #13JavaScript Essentials 71

notes, is binary oating-point arithmetic. Sort of like wanting your text translated into Russian but getting Belorussian. Similar, but not the same. More is going on here, but its beyond the scope of this article (not to mention the mathematical capabilities of this author). Workarounds for this problem are a favorite on computer science and developer forums. Your choice, to a point, comes down to the sort of calculations youre doing. The pros and cons of each are beyond the scope of this article, but the common choice is between the following: 1. Converting to integers and calculating on those instead, then converting back to decimals afterward; or 2. Tweaking your logic to allow for a range rather than a specic result. 3. So, for example, rather than
var num1 = 0.1, num2 = 0.2, shouldEqual = 0.3; alert(num1 + num2 == shouldEqual); //false

we would do this:
alert(num1 + num2 > shouldEqual - 0.001 && num1 + num2 < shouldEqual + 0.001); //true

Translated, this says that because 0.1 + 0.2 is apparently not 0.3, check instead that its more or less 0.3!!specically, within a range of 0.001 on either side of it. The obvious drawback is that, for very precise calculations, this will return inaccurate results. 10. UNDEFINED CAN BE DEFINED OK, lets end with a silly, rather inconsequential one. Strange as it might sound, undefined is not actually a reserved word in JavaScript, even

Smashing eBook #13JavaScript Essentials 72

though it has a special meaning and is the only way to determine whether a variable is undened. So:
var someVar; alert(someVar == undefined); //evaluates true

So far, so normal. But:


undefined = "I'm not undefined!"; var someVar; alert(someVar == undefined); //evaluates false!

You can also check Mozillas list of all reserved words in JavaScript for future reference.

Smashing eBook #13JavaScript Essentials 73

e Seven Deadly Sins Of JavaScript Implementation


Christian Heilmann
Using JavaScript has become increasingly easy over the last few years. Whereas back in the day we needed to know the quirks of every browser, now many libraries such as jQuery, YUI, Dojo and MooTools allow someone who doesnt even know JavaScript to spruce up boring HTML documents with impressive and shiny effects. By piggy-backing on the CSS selector engine, we have moved away from the complexity and inconsistencies of the DOM and made things much easier. If you look at some of the code that has been released, though, we do seem to have taken a step backwards. In gaining easier access, we also became a bit sloppy with our code. Finding clearly structured, easy-to-maintain jQuery code is quite tough, which is why many plug-ins do the same thing. Writing one yourself is faster than trying to fathom what other developers have done. The rules for solid, maintainable and secure JavaScript havent changed, though. So, lets run through the seven sins of JavaScript development that will bite you in the backside when you have to maintain the code later on or hand it over to another party. Weve all had to work with code written by other people. We have despaired over the lack of maintainability and documentation as well as weird logic. Funny enough, as developers, we started to see this as normal and got used to ignoring other peoples work and instead writing new code for the same problems over and over, as if we were subconsciously trying to secure our

Smashing eBook #13JavaScript Essentials 74

jobs by leaving behind unmaintainable codecode that only we understood, while complaining that no good solutions were out there.

Sins Of Our Fathers: Browser-Specic Code


One of the main obstacles that kept us from evolving as developers was that JavaScript was largely browser-specic. This was mainly because browsers did not support the standards (or were shipped before the governing bodies agreed on standards at all), and because we had to deliver our work before the competition and without extending the overly optimistic deadline set by our project managers. This happens to be one reason why Internet Explorer 6 refuses to die. Hundreds of expensive software packages that are being used in offices worldwide were built when this browser was state of the art. Thisand the monoculture that advocated using one software vendor for everything from the operating system to documents to spreadsheets to the browseris the reason why companies now cant simply discontinue support for it. It also means that newer versions of IE will always have to support the rendering mistakes of IE6 in one way or another. IE6 is the Frankenstein of the Internet, haunting its creators, terribly misunderstood by the townsfolk, who would sooner kill it, burn it and dance around it than make any sense of it. The good news is that you wont nd many scripts these days that begin with if(document.all){} and continue with else if(document.layers){}. If you do nd one, please send its creator a brief email encouraging them to move on or, better yet, to redirect their website to a better script that is actually being maintained.

Smashing eBook #13JavaScript Essentials 75

LIBRARIES TO THE RESCUE The job of JavaScript libraries such as jQuery, YUI, MooTools, Dojo and Glow is to make JavaScript development predictable and to relieve developers of the living hell that we call browser support. In other words, they x random bugs in browsers and free us to adopt standards without worrying that certain browsers wont recognize them. For example, the DOM method getElementById(id) should be straightforward: nd the element with the ID id and return it. But because some versions of IE and Opera also return elements that have the name attribute of id, jQuery solves the problem this way:
var elem; elem = document.getElementById( match[2] ); if ( elem ) { // Handle the case where IE and Opera return items // by name instead of ID if ( elem.id !== match[2] ) { return rootjQuery.find( selector ); } // Otherwise, we inject the element directly into the jQuery object this.length = 1; this[0] = elem; }

This is where libraries are awfully useful and is why JavaScript libraries are here to stay. Browsers will always do things wrong, and old browsers will not be upgraded by end users, either because of the aforementioned company regulations or because people simply dont care to keep up with the times.

Smashing eBook #13JavaScript Essentials 76

So, while the practice of building software for certain browsers is on the decline (at least for JavaScriptwith CSS, we have a whole other headache ahead of us), we still have to be mindful of certain sins.

Sin #1: Not Playing Nice With Other Scripts


Heres the rst one, which we still see a lot of on the Web. Sadly, it is very common in demo code for APIs and Web services: global variables, functions and DOM-1 event handlers. What do I mean by these? Consider the following: Every script in the HTML document has the same rights as the others and can, if need be, overwrite what other scripts have done before. If you dene a variable or function name, and some other include uses the same name, the initial one will be overwritten. The same applies to event handlers if you attach them the old-school onEvent way. Say you have the script script_one.js:
x = 5; function init(){ alert('script one init'); document.getElementsByTagName('h1')[0].onclick = function(){ this.style.background = 'blue'; } } alert('x is '+x); window.onload = init;

Smashing eBook #13JavaScript Essentials 77

And immediately after this one, you include another script, script_two.js:
x = 10; function init(){ alert('script two init'); document.getElementsByTagName('h1')[0].onclick = function(){ this.style.color = 'white'; } } alert('x is '+x); window.onload = init;

If you open this document in a browser, you will nd that x turns from 5 to 10 and that the rst init() is never called. The script two init alert() does not come up, nor does the h1 get a blue background when you click it. Only the text turns to white, which renders it invisible. The solution is not to use onEvent handlers, but rather the proper DOM level 2 event handlers (they dont work in IE, but lets not worry about that at the momentremember, this is what libraries are for). Furthermore, wrap your functions in another with a more unique name to prevent them from overriding each other.
var scriptOne = function(){ var x = 5; function init(){ alert('script one init'); document.getElementsByTagName('h1')[0].addEventListener( 'click', function(e){ var t = e.target; t.style.background = 'blue'; }, false ); } alert('x inside is '+x);

Smashing eBook #13JavaScript Essentials 78

return {init:init}; }(); window.addEventListener('load',scriptOne.init,false); alert('x outside is '+x); var scriptTwo = function(){ var x = 10; function init(){ alert('script two init'); document.getElementsByTagName('h1')[0].addEventListener( 'click', function(e){ var t = e.target; t.style.color = 'white'; }, false ); } alert('x inside is '+x); return {init:init}; }(); window.addEventListener('load',scriptTwo.init,false); alert('x outside is '+x);

If you run this in a browser (not Internet Explorer 6), everything will come up as you expect: x is rst 5, then 10 on the inside, and the heading turns blue and white when you click it. Both init() functions are called, too. You also get an error. Because x is not dened outside the functions, the alert('x outside is '+x); never works. The reason is that by moving the x into the scriptOne and scriptTwo functions and adding the var keyword in front of them, we have made them a part of those functions but hid them from the outside world. This is called a closure and is explained in detail here. It is probably the most powerful feature of JavaScript.

Smashing eBook #13JavaScript Essentials 79

Using closures and var keywords, you wont have the problem of variables with similar names overriding each other. This also applies in jQuery: you should namespace your functions. This can be tough to grasp, so lets look at a simpler example:
var x = 4; var f = 3; var me = 'Chris'; function init(){} function load(){}

All of these are global variables and functions now. Any other script having the same variables will override these. You can nest them in an object to avoid this:
var longerAndMoreDistinct = { x : 4, f : 3, me : 'Chris', init : function(){}, load : function(){} }

That way, only the longerAndMoreDistinct is global. If you want to run this function, you now have to call longerAndMoreDistinct.init() instead of init(). You can reach me as longerAndMoreDistinct.me and so on. I dont like this because I have to switch from one notation to another. So, we can do the following:
var longerAndMoreDistinct = function(){ var x = 4; var f = 3; var me = 'Chris'; function init(){} function load(){} }();

Smashing eBook #13JavaScript Essentials 80

You dene longerAndMoreDistinct as the outcome of a function without a name that gets immediately executed (this is the () on the last line). This now means that all of the variables and functions inside exist only in this world and cannot be accessed from outside at all. If you want to make them accessible from outside, you need to return them to the outside world:
var longerAndMoreDistinct = function(){ var x = 4; var f = 3; var me = 'Chris'; function load(){} return { init:function(){} } }();

Now init() is available as longerAndMoreDistinct.init() again. This construct of wrapping things in an anonymous function and returning some of them is called the Module pattern, and it keeps your variables safe. Personally, I still hate the shift in syntax, so I came up with the revealing module pattern. Instead of returning the real function, all I do is return a pointer to it:

Smashing eBook #13JavaScript Essentials 81

var longerAndMoreDistinct = function(){ var x = 4; var f = 3; var me = 'Chris'; function load(){} function init(){} return { init:init } }();

This way, I can make things either available or not available simply by adding to the object that is returned. If you dont need to give anything to the world and just want to run some code and keep all of your variables and function names safe, you can dispense with the name of the function:
(function(){ var x = 4; var f = 3; var me = 'Chris'; function load(){} function init(){} })();

Using var and wrapping code in this construct makes it inaccessible to the outside world, but still makes it execute. You may nd this to be complex stuff, but there is a good way to check your code. JSLint is a validator for JavaScript, much like the HTML or CSS validators, and it tells you all the things that might be wrong with your code.

Sin #2: Believing Instead Of Testing


The next big sin related to implementing JavaScript is expecting everything to go right: every parameter being in the right format, every HTML element
Smashing eBook #13JavaScript Essentials 82

you try to enhance being truly available, and every end user entering information in the right format. This will never be the case, and that last assumption is an especially bad one because it allows malicious users to inject dangerous code. When you write JavaScript and give it to the world or integrate it in a product that will be maintained by a third party, a little paranoia is a good thing. typeof is your friend. Regular expressions are your friend. indexOf(), split and length are your friends. In other words, do everything you can to make sure that incoming data is the right format. You will get a lot of errors with native JavaScript; if you do anything wrong, youll know what happened. The annoying thing about most JavaScript libraries is that when they fail to execute some functionality, they do it silently. The maintainer is left guessing and has to run through all the code and start debugging with stop points (orshudder!alerts()) to reverseengineer where you entered instable code. To avoid this, simply wrap whatever you can in a test case rather than try to access it.

Sin #3: Using

e Wrong Technology For

e Job

The biggest problem with JavaScript happens when you use the wrong tool for the job. It makes maintenance a nightmare and deteriorates the codes quality. Use tools for the jobs they were meant for. This means: Absolutely essential content and mark-up should be in HTML, regardless of the environment it will be displayed in. Any look and feel elements should be maintainable through CSS. You should not have to scour through JavaScript to change a color.

Smashing eBook #13JavaScript Essentials 83

Any interaction with the user that goes beyond hover effects (which, by denition, are an invitation to interact and not the interaction itself because they are inaccessible to keyboard users) should be done with JavaScript. The main reason why this is still a valid, pragmatic and sensible approach to development is that as Web technologies get muddled (for example, you can create content with CSS and JavaScript, animate and transform in CSS andif you really wantpaint with HTML), peoples skills and interests in these different technologies vary quite a bit. Semantic mark-up buffs are not much interested in applying closures in JavaScript. JavaScript developers are not much interested in the order of elements in CSS. And CSS fans arent keen to learn how to make a JavaScript animation run icker-free. This results in the same problems being solved over and over again, only with different technologies. This is a market-wide problem: a lot of state-ofthe-art Canvas tricks were done in Flash years ago, their impact debated and their problems xed. My favorite instance of this is when people write loops to hide a lot of elements on the page to make them available later on. Say this is your HTML:
<h2>Section 1</h2> <div class="section"> <p>Section 1 content</p> </div> <h2>Section 2</h2> <div class="section"> <p>Section 2 content</p> </div> <h2>Section 3</h2> <div class="section"> <p>Section 3 content</p>

Smashing eBook #13JavaScript Essentials 84

</div> <h2>Section 4</h2> <div class="section"> <p>Section 4 content</p> </div>

The normal jQuery solution for this would be:


$(document).ready(function(){ $('.section').hide(); $('h2').click(function(e){ $(this).next().toggle(); }) });

And then you realize that making the style of the current section deviate from that of the other sections would be great.
$(document).ready(function(){ $('.section').hide(); $('h2').click(function(e){ $(this).next().toggle(); $(this).next().css('background','#ccc'); $(this).next().css('border','1px solid #999'); $(this).next().css('padding','5px'); }) });

A few things are wrong with this. For starters, youve made it hard to maintain this by controlling the look and feel in JavaScript, not CSS (more on this later). Secondly, performance: while jQuery is amazingly speedy, a lot of code is still hidden under the hood in $('.section').hide(). The last, and very painful, performance issue is the copied and pasted lines that set the CSS. Dont ask jQuery to nd the next sibling four times and do something to it. You could store the next() in a variable, but even that is not needed if you chain. If you really need to set a lot of CSS in jQuery, use a map:

Smashing eBook #13JavaScript Essentials 85

$(document).ready(function(){ $('.section').hide(); $('h2').click(function(e){ $(this).next().toggle().css({ 'background':'#ffc', 'border':'1px solid #999', 'padding':'5px' }); }) });

What if you then want to allow only one of them to be open at any time? Inexperienced developers would do something like this:
$(document).ready(function(){ $('.section').hide(); $('h2').click(function(e){ $('.section').hide(); $(this).next().toggle().css({ 'background':'#ffc', 'border':'1px solid #999', 'padding':'5px' }); }) });

This does the job, but youre looping around the document and accessing the DOM a lot, which is slow. You can alleviate this by keeping the current open section in a variable:
$(document).ready(function(){ var current = false; $('.section').hide(); $('h2').click(function(e){ if(current){ current.hide(); } current = $(this).next(); current.toggle().css({ 'background':'#ffc', 'border':'1px solid #999',
Smashing eBook #13JavaScript Essentials 86

'padding':'5px' }); }) });

Predene the current section as false, and set it when you click the rst heading. You would then hide current only if it is true, thereby removing the need for another loop through all elements that have the class section. But here is the interesting thing: if all you want is to show and hide sections, you dont need any looping at all! CSS already goes through the document when it renders and applies classes. You just need to give the CSS engine something to hang on to, such as a class for the body:
$(document).ready(function(){ $('body').addClass('js'); var current = null; $('h2').click(function(e){ if(current){ current.removeClass('current'); } current = $(this).next().addClass('current'); }) });

By adding the class js to the body of the document and toggling the class current for the current section, you maintain control of the look and feel in CSS:

Smashing eBook #13JavaScript Essentials 87

<style type="text/css" media="screen"> .section{ border:1px solid #999; background:#ccc; } .js .section{ display:none; } .js .current{ display:block; border:1px solid #999; background:#ffc; } </style>

The beauty of this is that the handle will be re-usable by the CSS designer and maintainer. Anything without the .js selector would be the nonscripting-enabled version of a part of the document, and anything with the .js selector is applied only when JavaScript is available. And yes, you should think about the case when it is not.

Sin #4: Depending On JavaScript And Certain Input Devices


There is quite a discussion about the need to consider non-JavaScript environments in this day and age, but here is a fact: JavaScript can be turned off, and any JavaScript could break the page for the other scripts that are included. Given the akiness of code out there that may be running alongside yours and the instability of wireless and mobile connections, I for one want to build one thing: code that works. So, making sure that the most basic usage of your product does not depend on JavaScript is not just nice to have but essential if you expect people to actually use the product.

Smashing eBook #13JavaScript Essentials 88

Absolutely nothing is wrong with using JavaScript heavily. On the contrary, it makes the Web much smoother and saves us a lot of time if done right. But you should never promise functionality that doesnt work. And if you rely on JavaScript, this is exactly what youre doing. Ive already covered the effects of bad JavaScript in detail in the AJAX, JavaScript testing and security articles here on Smashing Magazine, but once again here are some simple steps you can take to make sure you dont break your promise to end users: Anything vital to the functionality of your product should not require JavaScript. Forms, links and server-side validation and re-direct scripts are your friends. If something depends on JavaScript, build it with JavaScript and add it to the document using the DOM or the equivalent method in your library of choice. If you add JavaScript functionality, make sure it works with the keyboard and mouse. Click and submit handlers are bullet-proof, whereas key and mouse events are aky and dont work on mobile devices. By writing clever back-end code that recognizes when data is required by JavaScript rather than building APIs that render HTML, you avoid having to do double-maintenance, which is an argument that many of the Everyone enables JavaScript zealots bring up a lot. For proof of this, check out the presentation on building Web applications using YQL and YUI that I gave a few weeks ago (video in English and German). WHEN JAVASCRIPT DEPENDENCE IS OKAY (TO A DEGREE) A lot of misunderstanding about JavaScript dependence stems from people making blanket statements based on the environments they work in. If you are a Google engineer working on Gmail, you would be hard pressed to think of why you would even bother working without JavaScript. The

Smashing eBook #13JavaScript Essentials 89

same goes for widget developers who work on OpenSocial widgets, mobile applications, Apple widgets and Adobe Air. In other words, if your environment already depends on JavaScript, then by all means dont bother with a fall-back. But do not take these closed environments and edge-case applications as the standard by which we should be measuring JavaScript. JavaScripts greatest power and greatest problem is its versatility. Saying that all websites can stand JavaScript because Gmail needs it is like saying that all cars should have a start button because they work great in Hybrids, or that hybrid cars should have massive tanks and cow catchers because they work great on Hummers. The technical feature set of a product depends on its implementation and target market. Different applications have different base functionality that needs to be satised in order to reach the largest audience and not block people out. CONSIDER THE USE CASES AND MAINTENANCE One fascinating aspect of JavaScript-dependent code is that, in many cases, people have simply not considered all the use cases (heres a great example). Take the following HTML:
<form action="#" id="f"> <div> <label for="search">Search</label> <input type="text" value="kittens" id="search"> <input type="submit" id="s" value="go"> </div> </form> <div id="results"></div>

Without JavaScript, this does nothing whatsoever. There is no sensible action attribute, and the text eld has no name attribute. So, even when you send the form off, the server wont get the information that the user has entered.

Smashing eBook #13JavaScript Essentials 90

Using jQuery and a JSON data source such as YQL, you can do a pure JavaScript search with this:
$('#s').click(function(event){ event.preventDefault(); $('<ul/>').appendTo('#results'); var url = $.getJSON('http://query.yahooapis.com/v1/public/yql?'+ 'q=select%20abstract%2Cclickurl%2Cdispurl%2Ctitle %20'+ 'from%20search.web%20where%20query%3D%22'+ $('#search').val() + '%22&format=json&'+ 'callback=?', function(data){ $.each(data.query.results.result, function(i,item){ $('<li><h3><a href="'+item.clickurl+'">'+ item.title+' ('+item.dispurl+')</a></h3><p>'+ (item.abstract || '') +'</p></li>'). appendTo("#results ul"); }); }); });

This works unless of course you are like me and prefer to send forms by hitting Enter rather than clicking the Submit button. Unless I tab through the whole form and focus on the Submit button, I get nothing.

Smashing eBook #13JavaScript Essentials 91

So, thats the rst thing to x. If you create forms, never use a click handler on the button. Instead, use the submit event of the form. This catches both the clicking Submit and hitting Enter cases. With one change, you now support all of the keyboard users out there, and the whole change is contained in the rst line:
$('#f').submit(function(event){ event.preventDefault(); $('<ul/>').appendTo('#results'); var url = $.getJSON('http://query.yahooapis.com/v1/public/yql?'+ 'q=select%20abstract%2Cclickurl%2Cdispurl%2Ctitle %20'+ 'from%20search.web%20where%20query%3D%22'+ $('#search').val() + '%22&format=json&'+ 'callback=?', function(data){ $.each(data.query.results.result, function(i,item){ $('<li><h3><a href="'+item.clickurl+'">'+ item.title+' ('+item.dispurl+')</a></h3><p>'+ (item.abstract || '') +'</p></li>'). appendTo("#results ul"); }); }); });

Weve now covered the rst case. But without JavaScript, the form still doesnt do anything. And another problem brings us to the next sin of writing JavaScript.

Sin #5: Making Maintenance Unnecessarily Hard


One thing that keeps great code off the Web is that our work environment, deadlines and hiring practices condition developers to build code for quick release, without considering how difficult maintaining that code will be later

Smashing eBook #13JavaScript Essentials 92

on. I once called JavaScript the village bicycle of Web design (slides here): anyone can go for a ride. Because the code is available in the open, future maintainers will be able to mess around with it and extend it any way they like. The sad thing is that the harder your code is to maintain, the more errors will be added to it, leading it to look more like alphabet soup than organized script. Take the above example. Those of you who havent worked with YQL and JSON-P for cross-domain AJAX undoubtedly had a What? moment looking at the code. Furthermore, keeping a lot of HTML in JavaScript easy to follow is hard, and guess what is the rst thing to change when a new design for the page comes along? Exactly: the HTML and CSS. So, to make it easier to maintain, I for one would shift all of the work to the back end, thus making the form work without JavaScript and keeping maintenance of all the HTML in the same document:
<?php if(isset($_GET['search'])){ $search = filter_input(INPUT_GET, 'search', FILTER_SANITIZE_ENCODED); $data = getdata($search); if($data->query->results){ $out = '<ul>'; foreach($data->query->results->result as $r){ $out .= "<li> <h3> <a href=\"{$r->clickurl}\">{$r->title} <span>({$r->dispurl})</span> </a> </h3> <p>{$r->abstract}</p> </li>";

Smashing eBook #13JavaScript Essentials 93

} $out .= '</ul>'; } else { $out = '<h3>Error: could not find any results</h3>'; } } if($_SERVER['HTTP_X_REQUESTED_WITH']!=''){ echo $out; die(); } ?> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Ajax Search with PHP API</title> <link rel="stylesheet" href="styles.css" type="text/css"> </head> <body> <form action="independent.php" id="f"> <div> <label for="search">Search</label> <input type="text" value="kittens" name="search" id="search"> <input type="submit" id="s" value="Go"> </div> </form> <div id="results"><?php if($out!=''){echo $out;}?></div> <script src="jquery.js"></script> <script src="ajaxform.js"></script> </body> </html>

Smashing eBook #13JavaScript Essentials 94

<?php function getdata($search){ $url = 'http://query.yahooapis.com/v1/public/yql?'. 'q=select%20abstract%2Cclickurl%2Cdispurl%2Ctitle %20'. 'from%20search.web%20where%20query%3D%22'. $search.'%22'. '&format=json'; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $output = curl_exec($ch); curl_close($ch); $data = json_decode($output); return $data; } ?>

Someone who doesnt understand PHP at all should still be able to change the HTML display without breaking the code. With this in place, the JavaScript boils down to a very simple script:
$('#f').submit(function(event){ event.preventDefault(); $.get('independent.php?search=' + $('#search').val(), function(data) { $('#results').html(data); } ); });

The normal way to make code more maintainable is to move everything that is likely to change away from the main functional part of the script into a conguration object at the very top of the script. You can return this as an object to the outside world to allow people to set it before they initialize the main functionality. So, one change we can make to our earlier examplealbeit a small one now, but that can change quickly when more requirements come inis to

Smashing eBook #13JavaScript Essentials 95

have a conguration section right up front that denes the CSS classes in use:
$(document).ready(function(){ /* Configuration object - change classes, IDs and string here */ var config = { /* CSS classes that get applied dynamically */ javascriptenabled:'js', currentsection:'current' } /* functionality starts here */ $('body').addClass(config.javascriptenabled); var current = null; $('h2').click(function(e){ if(current){ current.removeClass(config.currentsection); } current = $(this).next().addClass(config.currentsection); }) });

For more information on conguration objects and why they rock for maintenance, check out the blog post Providing Script Conguration Inline and Programatically. In summary, go over your code once more when you think youve nished with it and the next person is about to take it over.

Sin #6: Not Documenting Your Code


Good code documents itself is a terribly common and misguided belief. In my years as a developer, Ive found that my style of coding has changed constantly. What was common knowledge and best practice in 2004 might be forgotten or even considered poor style these days.

Smashing eBook #13JavaScript Essentials 96

Documenting all of the tricks and workarounds we do to make our code work in different browsers is denitely a good idea. This allows future maintainers to remove them when the targeted browser version becomes obsolete or a library function xes the issue. Commenting your code also allows the maintainer to trace it back to you should they need some piece of information, and it allows people who have stumbled across your script to include it in a larger solution or library (which has happened to me). Because JavaScripts tend replicate on the Web (in all of those blogs and script collections), it is also a way to make your name known. Dont go overboard with commenting, though. Obvious things dont need to be spelled out. I have found the following situations worthy of comment: Necessary hacks Browser hacks; content clean-up; things that should be supported server-side but are not yet. Sections that are likely to change Timely solutions; IDs, classes and strings (as explained earlier). Start of classes and reusable functions With name, author, version, date and license. Third-party code Give credit where credit is due. Sections with dependencies Some comment like, Needs the Google API with an own keythis one will not work on your server. In short, comment on anything that deviates from the normal ow of coding. I tend to use /* */ instead of // because it wont create a bug if people remove the line break by accident.

Smashing eBook #13JavaScript Essentials 97

SPECIAL CASE: COMMENTING OUT CODE One special case is commenting out sections that will be necessary in future releases or that depend on functionality not currently available. This can be amazingly useful but also a security risk, depending on what youre commenting out. For example, dont leave in any code that points to serverside APIs that are not available yet but could at any time be halfimplemented. Ive seen this before, where administrator links with the full unprotected path were commented out in the HTML. Still, commenting out can be very useful for debugging. One neat trick is the following:
/* myFunction('do something'); // */

This is now commented out. But by adding a single slash in front of the rst comment line, you will uncomment the whole block and make it live.
//* myFunction('do something'); // */

This trick makes it awfully easy to toggle whole blocks.

Sin #7: Optimizing For Machines, Not People


The last sin is over-optimizing JavaScript based on the scads of information about performance that are available to us. You will nd a lot of information on the Web about optimizing JavaScript for performance in the current browser environment. Notice that current browser environmentmuch
Smashing eBook #13JavaScript Essentials 98

information is browser- and version-specic and a necessary evil for now, but not necessarily in future. If your application is large or your website is high traffic, knowing and applying this information could make or break it. Again, though, a lot of this applies to edge cases that would have little impact on small projects and environments. This optimization does make it harder to maintain the code; some of the things we need to do to make browsers run fast on high-scale websites, such as writing out script nodes with document.write(), are downright nasty. When faced with the choice between making code cleaner and easier to amend, extend and understand on the one hand, and shaving two milliseconds off every page load on the other, I opt for the former. A lot of JavaScript optimization can be done through scripts. And rather than teach all developers on a project the ins and outs of JavaScript performance, an expert team (or even a tool) could optimize the code before it goes live. If you can do anything with machines to make the jobs of other machines easier, do it. The time has come for us to apply build processes as much to front-end code as we do to back-end code, instead of forcing ourselves to follow coding practices that go against the natural ow of writing code.

Smashing eBook #13JavaScript Essentials 99

A Quick Look Into


Christian Heilmann

e Math Of

Animations With JavaScript

In school, I hated math. It was a dire, dry and boring thing with stuffy old books and very theoretical problems. Even worse, a lot of the tasks were repetitive, with a simple logical change in every iteration (dividing numbers by hand, differentials, etc.). It was exactly the reason why we invented computers. Suffice it to say, a lot of my math homework was actually done by my trusty Commodore 64 and some lines of Basic, with me just copying the results later on. These tools and the few geometry lessons I had gave me the time and inspiration to make math interesting for myself. I did this rst and foremost by creating visual effects that followed mathematical rules in demos, intros and other seemingly pointless things. There is a lot of math in the visual things we do, even if we dont realize it. If you want to make something look natural and move naturally, you need to add a bit of physics and rounding to it. Nature doesnt work in right angles or linear acceleration. This is why zombies in movies are so creepy. This was covered here before in relation to CSS animation, but today lets go a bit deeper and look at the simple math behind the smooth looks.

Going From 0 To 1 Without Being Boring


If youve just started programming and are asked to go from 0 to 1 with a few steps in between, you would probably go for a for loop:

Smashing eBook #13JavaScript Essentials 100

for ( i = 0; i <= 1; i += 0.1 ) { x = i; y = i; }

This would result in a line on a graph that is 45 degrees. Nothing in nature moves with this precision:

A simple way to make this movement a bit more natural would be to simply multiply the value by itself:
for ( i = 0; i <= 1; i += 0.1 ) { x = i; y = i * i; }

This means that 0.1 is 0.01, 0.2 is 0.04, 0.3 is 0.09, 0.4 is 0.16, 0.5 is 0.25 and so on. The result is a curve that starts at and then gets steeper towards the end:

Smashing eBook #13JavaScript Essentials 101

You can make this even more pronounced by continuing to multiply or by using the to the power of Math.pow() function:
for ( i = 0; i <= 1; i += 0.1 ) { x = i; y = Math.pow( i, 4 ); }

Smashing eBook #13JavaScript Essentials 102

This is one of the tricks of the easing functions used in libraries such as jQuery and YUI, as well as in CSS transitions and animations in modern browsers. You can use this the same way, but there is an even simpler option for getting a value between 0 and 1 that follows a natural motion.

Not A Sin, Just A Natural Motion


Sine waves are probably the best thing ever for smooth animation. They happen in nature: witness a spring with a weight on it, ocean waves, sound and light. In our case, we want to move from 0 to 1 smoothly. To create a movement that goes from 0 to 1 and back to 0 smoothly, we can use a sine wave that goes from 0 to in a few steps. The full sine wave

Smashing eBook #13JavaScript Essentials 103

going from 0 to 2 (i.e. a whole circle) would result in values from -1 to 1, and we dont want that (yet).
var counter = 0; // 100 iterations var increase = Math.PI / 100; for ( i = 0; i <= 1; i += 0.01 ) { x = i; y = Math.sin(counter); counter += increase; }

A quick aside on numbers for sine and cosine: Both Math.sin() and Math.cos() take as the parameter an angle that should be in radians. As humans, however, degrees ranging from 0 to 360 are much easier to read. Thats why you can and should convert between them with this simple formula:
Smashing eBook #13JavaScript Essentials 104

var toRadian = Math.PI / 180; var toDegree = 180 / Math.PI; var angle = 30; var angleInRadians = angle * toRadian; var angleInDegrees = angleInRadians * toDegree;

Back to our sine waves. You can play with this a lot. For example, you could use the absolute value of a full 2 loop:
var counter = 0; // 100 iterations var increase = Math.PI * 2 / 100;

for ( i = 0; i <= 1; i += 0.01 ) { x = i; y = Math.abs( Math.sin( counter ) ); counter += increase; }

Smashing eBook #13JavaScript Essentials 105

But again, this looks dirty. If you want the full up and down, without a break in the middle, then you need to shift the values. You have to half the sine and then add 0.5 to it:
var counter = 0; // 100 iterations var increase = Math.PI * 2 / 100; for ( i = 0; i <= 1; i += 0.01 ) { x = i; y = Math.sin( counter ) / 2 + 0.5; counter += increase; }

So, how can you use this? Having a function that returns -1 to 1 to whatever you feed it can be very cool. All you need to do is multiply it by the values that you want and add an offset to avoid negative numbers. For example, check out this sine movement demo:

Smashing eBook #13JavaScript Essentials 106

Looks neat, doesnt it? A lot of the trickery is already in the CSS:
.stage { width:200px; height:200px; margin:2em; position:relative; background:#6cf; overflow:hidden; } .stage div { line-height:40px; width:100%; text-align:center; background:#369; color:#fff; font-weight:bold; position:absolute; }

The stage element has a xed dimension and is positioned relative. This means that everything that is positioned absolutely inside it will be relative to the element itself.

Smashing eBook #13JavaScript Essentials 107

The div inside the stage is 40 pixels high and positioned absolutely. Now, all we need to do is move the div with JavaScript in a sine wave:
var banner = document.querySelector( '.stage div' ), start = 0; function sine(){ banner.style.top = 50 * Math.sin( start ) + 80 + 'px'; start += 0.05; } window.setInterval( sine, 1000/30 );

The start value changes constantly, and with Math.sin() we get a nice wave movement. We multiply this by 50 to get a wider wave, and we add 80 pixels to center it in the stage element. Yes, the element is 200 pixels high and 100 is half of that, but because the banner is 40 pixels high, we need to subtract half of that to center it. Right now, this is a simple up-and-down movement. Nothing stops you, though, from making it more interesting. The multiplying factor of 50, for example, could be a sine wave itself with a different value:
var banner = document.querySelector( '.stage div' ), start = 0, multiplier = 0; function sine(){ multiplier = 50 * Math.sin( start * 2 ); banner.style.top = multiplier * Math.sin( start ) + 80 + 'px'; start += 0.05; } window.setInterval( sine, 1000/30 );

The result of this is a banner that seems to tentatively move up and down. Back in the day and on the very slow Commodore 64, calculating the sine wave live was too slow. Instead, we had tools to generate sine tables (arrays, if you will), and we plotted those directly. One of the tools for creating great sine waves so that you could have bouncing scroll texts was the Wix Bouncer:
Smashing eBook #13JavaScript Essentials 108

Circles In

e Sand, Round And Round

Circular motion is a thing of beauty. It pleases the eye, reminds us of spinning wheels and the earth we stand on, and in general has a this is not computer stuff feel to it. The math of plotting something on a circle is not hard. It goes back to Pythagoras, who, as rumor has it, drew a lot of circles in the sand until he found his famous theorem. If you want to use all the good stuff that comes from this theorem, then try to nd a triangle with a right angle. If this triangles hypothenuse is 1, then you can easily calculate the horizontal leg as the cosine of the angle and the vertical leg as the sine of the angle:

Smashing eBook #13JavaScript Essentials 109

How is this relevant to a circle? Well, it is pretty simple to nd a right-angle triangle in a circle to every point of it:

Smashing eBook #13JavaScript Essentials 110

This means that if you want to plot something on a circle (or draw one), you can do it with a loop and sine and cosine. A full circle is 360, or 2 in radians. We could have a go at it!!but rst, some plotting code needs to be done.

A Quick DOM Plo ing Routine


Normally, my weapon of choice here would be canvas, but in order to play nice with older browsers, lets do it in plain DOM. The following helper function adds div elements to a stage element and allows us to position them, change their dimensions, set their color, change their content and rotate them without having to go through the annoying style settings on DOM elements.

Smashing eBook #13JavaScript Essentials 111

Plot = function ( stage ) { this.setDimensions = function( x, y ) { this.elm.style.width = x + 'px'; this.elm.style.height = y + 'px'; this.width = x; this.height = y; } this.position = function( x, y ) { var xoffset = arguments[2] ? 0 : this.width / 2; var yoffset = arguments[2] ? 0 : this.height / 2; this.elm.style.left = (x - xoffset) + 'px'; this.elm.style.top = (y - yoffset) + 'px'; this.x = x; this.y = y; }; this.setbackground = function( col ) { this.elm.style.background = col; } this.kill = function() { stage.removeChild( this.elm ); } this.rotate = function( str ) { this.elm.style.webkitTransform = this.elm.style.MozTransform = this.elm.style.OTransform = this.elm.style.transform = 'rotate('+str+')'; } this.content = function( content ) { this.elm.innerHTML = content; } this.round = function( round ) { this.elm.style.borderRadius = round ? '50%/50%' : ''; } this.elm = document.createElement( 'div' ); this.elm.style.position = 'absolute'; stage.appendChild( this.elm ); };

Smashing eBook #13JavaScript Essentials 112

The only things that might be new here are the transformation with different browser prexes and the positioning. People often make the mistake of creating a div with the dimensions w and h and then set it to x and y on the screen. This means you will always have to deal with the offset of the height and width. By subtracting half the width and height before positioning the div, you really set it where you want it!!regardless of the dimensions. Heres a proof:

Now, lets use that to plot 10 rectangles in a circle, shall we?

Smashing eBook #13JavaScript Essentials 113

var stage = document.querySelector('.stage'), plots = 10; increase = Math.PI * 2 / plots, angle = 0, x = 0, y = 0; for( var i = 0; i < plots; i++ ) { var p = new Plot( stage ); p.setBackground( 'green' ); p.setDimensions( 40, 40 ); x = 100 * Math.cos( angle ) + 200; y = 100 * Math.sin( angle ) + 200; p.position( x, y );

Smashing eBook #13JavaScript Essentials 114

angle += increase; }

We want 10 things in a circle, so we need to nd the angle that we want to put them at. A full circle is two times Math.PI, so all we need to do is divide this. The x and y position of our rectangles can be calculated by the angle we want them at. The x is the cosine, and the y is the sine, as explained earlier in the bit on Pythagoras. All we need to do, then, is center the circle that were painting in the stage (200,200 is the center of the stage), and we are done. Weve painted a circle with a radius of 100 pixels on the canvas in 10 steps. The problem is that this looks terrible. If we really want to plot things on a circle, then their angles should also point to the center, right? For this, we need to calculate the tangent of the right-angle square, as explained in this charming Math is fun page. In JavaScript, we can use Math.atan2() as a shortcut. The result looks much better:

Smashing eBook #13JavaScript Essentials 115

var stage = document.querySelector('.stage'), plots = 10; increase = Math.PI * 2 / plots, angle = 0, x = 0, y = 0; for( var i = 0; i < plots; i++ ) { var p = new Plot( stage ); p.setBackground( 'green' ); p.setDimensions( 40, 40 ); x = 100 * Math.cos( angle ) + 200; y = 100 * Math.sin( angle ) + 200; p.rotate( Math.atan2( y - 200, x - 200 ) + 'rad' );

Smashing eBook #13JavaScript Essentials 116

p.position( x, y ); angle += increase; }

Notice that the rotate transformation in CSS helps us heaps in this case. Otherwise, the math to rotate our rectangles would be much less fun. CSS transformations also take radians and degrees as their value. In this case, we use rad; if you want to rotate with degrees, simply use deg as the value. How about animating the circle now? Well, the rst thing to do is change the script a bit, because we dont want to have to keep creating new plots. Other than that, all we need to do to rotate the circle is to keep increasing the start angle:
var stage = document.querySelector('.stage'), plots = 10; increase = Math.PI * 2 / plots, angle = 0, x = 0, y = 0, plotcache = []; for( var i = 0; i < plots; i++ ) { var p = new Plot( stage ); p.setBackground( 'green' ); p.setDimensions( 40, 40 ); plotcache.push( p ); } function rotate(){ for( var i = 0; i < plots; i++ ) { x = 100 * Math.cos( angle ) + 200; y = 100 * Math.sin( angle ) + 200; plotcache[ i ].rotate( Math.atan2( y - 200, x - 200 ) + 'rad' ); plotcache[ i ].position( x, y ); angle += increase; } angle += 0.06; } setInterval( rotate, 1000/30 );

Smashing eBook #13JavaScript Essentials 117

Want more? How about a rotating text message based on this? The tricky thing about this is that we also need to turn the characters 90 on each iteration:

var stage = document.querySelector('.stage'), message = 'Smashing Magazine '.toUpperCase(), plots = message.length; increase = Math.PI * 2 / plots, angle = -Math.PI, turnangle = 0, x = 0, y = 0, plotcache = []; for( var i = 0; i < plots; i++ ) { var p = new Plot( stage ); p.content( message.substr(i,1) ); p.setDimensions( 40, 40 );

Smashing eBook #13JavaScript Essentials 118

plotcache.push( p ); } function rotate(){ for( var i = 0; i < plots; i++ ) { x = 100 * Math.cos( angle ) + 200; y = 100 * Math.sin( angle ) + 200; // rotation and rotating the text 90 degrees turnangle = Math.atan2( y - 200, x - 200 ) * 180 / Math.PI + 90 + 'deg'; plotcache[ i ].rotate( turnangle ); plotcache[ i ].position( x, y ); angle += increase; } angle += 0.06; } setInterval( rotate, 1000/40 );

Again, nothing here is xed. You can make the radius of the circle change constantly, as we did with the bouncing banner message earlier (below is only an excerpt):
multiplier = 80 * Math.sin( angle ); for( var i = 0; i < plots; i++ ) { x = multiplier * Math.cos( angle ) + 200; y = multiplier * Math.sin( angle ) + 200; turnangle = Math.atan2( y - 200, x - 200 ) * 180 / Math.PI + 90 + 'deg'; plotcache[ i ].rotate( turnangle ); plotcache[ i ].position( x, y ); angle += increase; } angle += 0.06;

And, of course, you can move the center of the circle, too:
rx = 50 * Math.cos( angle ) + 200; ry = 50 * Math.sin( angle ) + 200; for( var i = 0; i < plots; i++ ) { x = 100 * Math.cos( angle ) + rx; y = 100 * Math.sin( angle ) + ry;

Smashing eBook #13JavaScript Essentials 119

turnangle = Math.atan2( y - ry, x - rx ) * 180 / Math.PI + 90 + 'deg'; plotcache[ i ].rotate( turnangle ); plotcache[ i ].position( x, y ); angle += increase; } angle += 0.06;

For a nal tip, how about allowing only a certain range of coordinates?
function rotate() { rx = 70 * Math.cos( angle ) + 200; ry = 70 * Math.sin( angle ) + 200; for( var i = 0; i < plots; i++ ) { x = 100 * Math.cos( angle ) + rx; y = 100 * Math.sin( angle ) + ry; x = contain( 70, 320, x ); y = contain( 70, 320, y ); turnangle = Math.atan2( y - ry, x - rx ) * 180 / Math.PI + 90 + 'deg'; plotcache[ i ].rotate( turnangle ); plotcache[ i ].position( x, y ); angle += increase; } angle += 0.06; } function contain( min, max, value ) { return Math.min( max, Math.max( min, value ) ); }

SUMMARY This was just a quick introduction to using exponentials and sine waves and to plotting things on a circle. Have a go with the code, and play with the numbers. It is amazing how many cool effects you can create with a few changes to the radius or by multiplying the angles. To make it easier for you to do this, below are the examples on JSFiddle to play with: Sine bouncing message

Smashing eBook #13JavaScript Essentials 120

Double sine bouncing message Offset issue with plotting Distributing elements on a circle Distributing elements on a circle with correct angles Rotating a circle of boxes Oscillating rotating message Rotating message in a circle movement Boxed rotated message scroller

Smashing eBook #13JavaScript Essentials 121

Searchable Dynamic Content With AJAX Crawling


Zack Grossbart
Google Search likes simple, easy-to-crawl websites. You like dynamic websites that show off your work and that really pop. But search engines cant run your JavaScript. That cool AJAX routine that loads your content is hurting your SEO. Googles robots parse HTML with ease; they can pull apart Word documents, PDFs and even images from the far corners of your website. But as far as theyre concerned, AJAX content is invisible.

e Problem With AJAX


AJAX has revolutionized the Web, but it has also hidden its content. If you have a Twitter account, try viewing the source of your prole page. There are no tweets there!!just code! Almost everything on a Twitter page is built dynamically through JavaScript, and the crawlers cant see any of it. Thats why Google developed AJAX crawling. Because Google cant get dynamic content from HTML, you will need to provide it another way. But there are two big problems: Google wont run your JavaScript, and it doesnt trust you. Google indexes the entire Web, but it doesnt run JavaScript. Modern websites are little applications that run in the browser, but running those applications as they index is just too slow for Google and everyone else.

Smashing eBook #13JavaScript Essentials 122

The trust problem is trickier. Every website wants to come out rst in search results; your website competes with everyone elses for the top position. Google cant just give you an API to return your content because some websites use dirty tricks like cloaking to try to rank higher. Search engines cant trust that youll do the right thing. Google needs a way to let you serve AJAX content to browsers while serving simple HTML to crawlers. In other words, you need the same content in multiple formats.

Two URLs For

e Same Content

Lets start with a simple example. Im part of an open-source project called Spiffy UI. Its a Google Web Toolkit (GWT) framework for REST and rapid development. We wanted to show off our framework, so we made SpiffyUI.org using GWT. GWT is a dynamic framework that puts all of our content in JavaScript. Our index.html le looks like this:
<body> <script type="text/javascript" language="javascript" src="org.spiffyui.spsample.index.nocache.js"></script> </body>

Everything is added to the page with JavaScript, and we control our content with hash tags (Ill explain why a little later). Every time you move to another page in our application, you get a new hash tag. Click on the CSS link and youll end up here:
http://www.spiffyui.org#css

The URL in the address bar will look like this in most browsers:
http://www.spiffyui.org/?css

Smashing eBook #13JavaScript Essentials 123

Weve xed it up with HTML5. Ill show you how later in this article. This simple hash works well for our application and makes it bookmarkable, but it isnt crawlable. Google doesnt know what a hash tag means or how to get the content from it, but it does provide an alternate method for a website to return content. So, we let Google know that our hash is really JavaScript code instead of just an anchor on the page by adding an exclamation point (a bang), like this:
http://www.spiffyui.org#!css

This hash bang is the secret sauce in the whole AJAX crawling scheme. When Google sees these two characters together, it knows that more content is hidden by JavaScript. It gives us a chance to return the full content by making a second request to a special URL:
http://www.spiffyui.org?_escaped_fragment_=css

The new URL has replaced the #! with ?_escaped_fragment_=. Using a URL parameter instead of a hash tag is important, because parameters are sent to the server, whereas hash tags are available only to the browser. That new URL lets us return the same content in HTML format when Googles crawler requests it. Confused? Lets look at how it works, step by step.

Snippets Of HTML
The whole page is rendered in JavaScript. We needed to get that content into HTML so that it is accessible to Google. The rst step was to separate SpiffyUI.org into snippets of HTML. Google still thinks of a website as a set of pages, so we needed to serve our content that way. This was pretty easy with our application, because we

Smashing eBook #13JavaScript Essentials 124

have a set of pages, and each one is a separate logical section. The rst step was to make the pages bookmarkable. BOOKMARKING Most of the time, JavaScript just changes something within the page: when you click that button or pop up that panel, the URL of the page does not change. Thats ne for simple pages, but when youre serving content through JavaScript, you want give users unique URLs so that they can bookmark certain areas of your application. JavaScript applications can change the URL of the current page, so they usually support bookmarking via the addition of hash tags. Hash tags work better than any other URL mechanism because theyre not sent to the server; theyre the only part of the URL that can be changed without having to refresh the page. The hash tag is essentially a value that makes sense in the context of your application. Choose a tag that is logical for the area of your application that it represents, and add it to the hash like this:
http://www.spiffyui.org#css

When a user accesses this URL again, we use JavaScript to read the hash tag and send the user to the page that contains the CSS. You can choose anything you want for your hash tag, but try to keep it readable, because users will be looking at it. We give our hashes tags like css, rest and security. Because you can name the hash tag anything you want, adding the extra bang for Google is easy. Just slide it between the hash and the tag, like this:
http://www.spiffyui.org#!css

Smashing eBook #13JavaScript Essentials 125

You can manage all of your hash tags manually, but most JavaScript history frameworks will do it for you. All of the plug-ins that support HTML4 use hash tags, and many of them have options for making URLs bookmarkable. We use History.js by Ben Lupton. Its easy to use, its open source, and it has excellent support for HTML5 history integration. Well talk more about that shortly. SERVING UP SNIPPETS The hash tag makes an application bookmarkable, and the bang makes it crawlable. Now Google can ask for special escaped-fragment URLs like so:

When the crawler accesses our ugly URL, we need to return simple HTML. We cant handle that in JavaScript because the crawler doesnt run JavaScript in the crawler. So, it all has to come from the server.
Smashing eBook #13JavaScript Essentials 126

You can implement your server in PHP, Ruby or any other language, as long as it delivers HTML. SpiffyUI.org is a Java application, so we deliver our content with a Java servlet. The escaped fragment tells us what to serve, and the servlet gives us a place to serve it from. Now we need the actual content. Getting the content to serve is tricky. Most applications mix the content in with the code; but we dont want to parse the readable text out of the JavaScript. Luckily, Spiffy UI has an HTML-templating mechanism. The templates are embedded in the JavaScript but also included on the server. When the escaped fragment looks for the ID css, we just have to serve CSSPanel.html. The template without any styling looks very plain, but Google just needs the content. Users see our page with all of the styles and dynamic features:

Smashing eBook #13JavaScript Essentials 127

Google gets only the unstyled version:

Smashing eBook #13JavaScript Essentials 128

You can see all of the source code for our SiteMapServlet.java servlet. This servlet is mostly just a look-up table that takes an ID and serves the associated content from somewhere on our server. Its called SiteMapServlet.java because this class also handles the generation of our site map.

Smashing eBook #13JavaScript Essentials 129

Tying It All Together With A Site Map


Our site map tells the crawler whats available in our application. Every website should have a site map; AJAX crawling doesnt work without one. Site maps are simple XML documents that list the URLs in an application. They can also include data about the priority and update frequency of the apps pages. Normal entries for site maps look like this:
<url> <loc>http://www.spiffyui.org/</loc> <lastmod>2011-07-26</lastmod> <changefreq>daily</changefreq> <priority>1.0</priority> </url>

Our AJAX-crawlable entries look like this:

<url> <loc>http://www.spiffyui.org/#!css</loc> <lastmod>2011-07-26</lastmod> <changefreq>daily</changefreq> <priority>0.8</priority> </url>

The hash bang tells Google that this is an escaped fragment, and the rest works like any other page. You can mix and match AJAX URLs and regular URLs, and you can use only one site map for everything. You could write your site map by hand, but there are tools that will save you a lot of time. The key is to format the site map well and submit it to Google Webmaster Tools.

Smashing eBook #13JavaScript Essentials 130

Google Webmaster Tools


Google Webmaster Tools gives you the chance to tell Google about your website. Log in with your Google ID, or create a new account, and then verify your website.

Smashing eBook #13JavaScript Essentials 131

Once youve veried, you can submit your site map and then Google will start indexing your URLs. And then you wait. This part is maddening. It took about two weeks for SpiffyUI.org to show up properly in Google Search. I posted to the help forums half a dozen times, thinking it was broken. Theres no easy way to make sure everything is working, but there are a few tools to help you see whats going on. The best one is Fetch as Googlebot, which shows you exactly what Google sees when it crawls your website. You can access it in your dashboard in Google Webmaster Tools under Diagnostics.

Smashing eBook #13JavaScript Essentials 132

Enter a hash bang URL from your website, and click Fetch. Google will tell you whether the fetch has succeeded and, if it has, will show you the content it sees.

Smashing eBook #13JavaScript Essentials 133

If Fetch as Googlebot works as expected, then youre returning the escaped URLs correctly. But you should check a few more things: Validate your site map. Manually try the URLs in your site map. Make sure to try the hash-bang and escaped versions.

Smashing eBook #13JavaScript Essentials 134

Check the Google result for your website by searching for site:www.yoursite.com.

Making Pre y URLs With HTML5


Twitter leaves the hash bang visible in its URLs, like this:
http://twitter.com/#!/ZackGrossbart This works well for AJAX crawling, but again, its slightly ugly. You can make

your URLs prettier by integrating HTML5 history. Spiffy UI uses HTML5 history integration to turn a hash-bang URL like this
http://www.spiffyui.org#!css

into a pretty URL like this:


http://www.spiffyui.org?css

HTML5 history makes it possible to change this URL parameter, because the hash tag is the only part of the URL that you can change in HTML4. If you change anything else, the entire page reloads. HTML5 history changes the entire URL without refreshing the page, and we can make the URL look any way we want. This nicer URL works in our application, but we still list the hash-bang version on our site map. And when browsers access the hash-bang URL, we change it to the nicer one with a little JavaScript.

Cloaking
Earlier, I mentioned cloaking. It is the practice of trying to boost a websites ranking in search results by showing one set of pages to Google and

Smashing eBook #13JavaScript Essentials 135

another to regular browsers. Google doesnt like cloaking and may remove offending websites from its search index. AJAX-crawling applications always show different results to Google than to regular browsers, but it isnt cloaking if the HTML snippets contain the same content that the user would see in the browser. The real mystery is how Google can tell whether a website is cloaking or not; crawlers cant compare content programmatically because they dont run JavaScript. Its all part of Googles Googley power. Regardless of how its detected, cloaking is a bad idea. You might not get caught, but if you do, youll be removed from the search index.

Hash Bang Is A Li le Ugly, But It Works


Im an engineer, and my rst response to this scheme is Yuck! It just feels wrong; were warping the purpose of URLs and relying on magic strings. But I understand where Google is coming from; the problem is extremely difficult. Search engines need to get useful information from inherently untrustworthy sources: us. Hash bangs shouldnt replace every URL on the Web. Some websites have had serious problems with hash-bang URLs because they rely on JavaScript to serve content. Simple pages dont need hash bangs, but AJAX pages do. The URLs do look a bit ugly, but you can x that with HTML5. FURTHER READING Weve covered a lot in this article. Supporting AJAX crawling means that you need to change your clients code and your servers code. Here are some links to nd out more: Making AJAX Applications Crawlable, Google Code

Smashing eBook #13JavaScript Essentials 136

Session History and Navigation, HTML5 specication, section 5.4 sitemaps.org Google Webmaster Tools Spiffy UI source code, with a complete example of AJAX crawling. Thanks to Kristen Riley for help with some of the images in this article.

Smashing eBook #13JavaScript Essentials 137

Authors
Addy Osmani
Addy Osmani is a JavaScript blogger & UI Developer for AOL based in London, England. He is also a member of the jQuery [Bug Triage/Docs/ Front-end] teams where he assists with bugs, documentation and community updates. Most recently he's been nominated for the .net 'Brilliant Newcomer' award.

Andy Croxall
Andy Croxall is a Web developer from Wandsworth, London, England. He is a Javascript specialist and is an active member of the jQuery community, posting plugins and extensions. He has worked for clients ranging from the London Stock Exchange to Durex. You can keep up with him and his projects and creations on his

Christian Heilmann
An international Developer Evangelist working for Mozilla in the lovely town of London, England.

Zack Grossbart
Zack Grossbart is an engineer, designer, and author. He's a founding member of the Spiffy UI project, the architect of the WordPress Editorial Calendar, and a Consulting Engineer with NetIQ. Zack began loading DOS from a oppy disk when he was ve years old. He rst worked professionally

Smashing eBook #13JavaScript Essentials 138

with computers when he was 15 and started his rst software company when he was 16. Zack lives in Cambridge, Massachusetts with his wife and daughter.

Smashing eBook #13JavaScript Essentials 139

Das könnte Ihnen auch gefallen