Lessons learned from JavaScript quizzes

Nicholas answered three JavaScript quizzes in his blog. I am not interested in quiz like the one given below

var num1 = 5,
    num2 = 10,
    result = num1+++num2;

However some of the questions helped me learn a few things.

Questions from quiz

Recently there was a quiz out.

This was question #5 in the original blog. I have modified the quiz a little bit to suit my needs.

var x = 10;
var foo = {
  x: 20,
  bar: function () {
    var x = 30;
    return this.x;
  }
};

// 1
console.log(foo.bar());

// 2
console.log((foo.bar)());

// 3
console.log(foo.bar.call());

I got the first two answers wrong. In JavaScript a variable and a property are two different things. When this.xyx is invoked then JavaScript engine is looking for property called xyz.

var  bar = function () {
  var x = 30;
  return this.x;
};
console.log(bar()); //=> undefined

In the above case output is undefined. This is because this refers to a property named x and since no such property was found undefined is the answer.

var foo = {
  x: 20,
  bar: function () {
    return x;
  }
};
console.log(foo.bar());

Above code causes ReferenceError because x is not defined. Same thoery applies here. In this case x is a variable and since no such variable was found code failed.

Coming back to the third part of the original question. This one uses call.

console.log(foo.bar.call());

First arugument of call or apply method determines what this would be inside the function. If no argument is passed is passed then JavaScript engine assumes that this would be global scope which translates to this being window. Hence the answer is 10 in this case.

Questions from another quiz

There was another quiz .

In the original blog this is question #2.

var x = 5,
    o = {
        x: 10,
        doIt: function doIt(){
            var x = 20;
            setTimeout(function(){
                alert(this.x);
            }, 10);
        }
    };
o.doIt();

The key thing to remember here is that All functions passed into setTimeout() are executed in the global scope .

In the original blog this is question #5.

var o = {
        x: 8,

        valueOf: function(){
            return this.x + 2;
        },
        toString: function(){
            return this.x.toString();
        }
    },
    result = o < "9";

alert(o);

The thing to remember here is that when comparison is done then valueOf method is called on the object.

Questions from quiz

This is question #1 in the original blog.

if (!("a" in window)) {
  var a = 1;
}
alert(a);

I knew that all the variable declarations are hoisted up but somehow failed to apply that logic here. Please see the original blog for a detailed answer.

This is question #5 in the original blog.

function a() {
  alert(this);
}
a.call(null);

I knew that if nothing is passed to call method then this becomes global but did not know that if null is passed then also this becomes global.

Practical example of need for prototypal inheritance

Alex Sexton wrote a wonderful article on how to use inheritance pattern to manage large piece of code. His code also has a practical need for prototypal inheritance for writing modular code.

Creating standard jQuery plugin

Given below is code that does exactly what Alex’s code does.

$(function() {
	$.fn.speaker = function(options) {
		if (this.length) {
			return this.each(function() {

				var defaultOptions = {
					name: 'No name'
				};
				options = $.extend({},
				defaultOptions, options);

				var $this = $(this);

				$this.html('<p>' + options.name + '</p>');

				var fn = {};
				fn.speak = function(msg) {
					$this.append('<p>' + msg + '</p>' );
				};

				$.data(this, 'speaker', fn);
			});
		}
	};
});

For smaller plugins this code is not too bad. However if the plugin is huge then it presents one big problem. The code for business problem and the code that deals with jQuery is all mixed in. What it means is that if tomorrow same functionality needs to be implemented for Prototype framework then it is not clear what part of code deals with framework and what part deals with business logic.

Separating business logic and framework code

Given below is code that separates business logic and framework code.

var Speaker = function(opts, elem) {

	this._build = function() {
		this.$elem.html('<h1>' + options.name + '</h1>');
	};

	this.speak = function(msg) {
		this.$elem.append('<p>' + msg + '</p>');
	};

	var defaultOptions = {
		name: 'No name'
	};

	var options = $.extend({},
	defaultOptions, this.opts);

	this.$elem = $(elem);

	this._build();

};

$(function() {
	$.fn.speaker = function(options) {
		if (this.length) {
			return this.each(function() {
				var mySpeaker = new Speaker(options, this);
				$.data(this, 'speaker', mySpeaker);
			});
		}
	};
});

This code is an improvement over first iteration. However the whole business logic is captured inside a function. This code can be further improved by embracing object literal style of coding.

Final Improvement

Third and final iteration of the code is the code presented by Alex.

var Speaker = {
	init: function(options, elem) {
		this.options = $.extend({},
		this.options, options);

		this.elem = elem;
		this.$elem = $(elem);

		this._build();
	},
	options: {
		name: "No name"
	},
	_build: function() {
		this.$elem.html('<h1>' + this.options.name + '</h1>');
	},
	speak: function(msg) {
		this.$elem.append('<p>' + msg + '</p>');
	}
};

// Make sure Object.create is available in the browser (for our prototypal inheritance)
if (typeof Object.create !== 'function') {
	Object.create = function(o) {
		function F() {}
		F.prototype = o;
		return new F();
	};
}

$(function() {
	$.fn.speaker = function(options) {
		if (this.length) {
			return this.each(function() {
				var mySpeaker = Object.create(Speaker);
				mySpeaker.init(options, this);
				$.data(this, 'speaker', mySpeaker);
			});
		}
	};

Notice the Object.create pattern Alex used. The business logic code was converted from a function to a JavaScript object. However the problem is that you can’t create a new on that object. And you need to create new object so that you could dole out new objects to each element. Object.create pattern comes to rescue.

This pattern takes a standard Object and returns an instance of a function. This function has the input object set as prototype. So you get a brand new object for each element and you get to have all your business logic in object literal way and not in a function. If you want to know more about prototypal inheritance then you can read more about it in previous blog .

Object.create is now part of ECMAScript 5 .

Prototypal inheritance in JavaScript

One of the key features of JavaScript language is its support for prototype method. This feature could be used to bring inheritance in JavaScript.

In the beginning there was duplication

function Person(dob){
  this.dob = dob;
  this.votingAge = 21;
}
function Developer(dob, skills){
  this.dob = dob;
  this.skills = skills || '';
  this.votingAge = 21;
}
// create a Person instance
var person = new Person('02/02/1970');

//create a Developer instance
var developer = new Developer('02/02/1970', 'JavaScript');

As you can see both Person and Developer objects have votingAge property. This is code duplication. This is an ideal case where inheritance can be used.

prototype method

Whenever you create a function, that function instantly gets a property called prototype. The initial value of this prototype property is empty JavaScript object {} .

var fn = function(){};
fn.prototype //=> {}

JavaScript engine while looking up for a method in a function first searches for method in the function itself. Then the engine looks for that method in that functions’ prototype object.

Since prototype itself is a JavaScript object, more methods could be added to this JavaScript object.

var fn = function(){};
fn.prototype.author_name = 'John';
var f = new fn();
f.author_name; //=> John

Refactoring code to make use of prototype method

Currently Person function is defined like this.

function Person(dob){
  this.dob = dob;
  this.votingAge = 21;
}

Problem with above code is that every time a new instance of Person is created, two new properties are created and they take up memory. If a million objects are created then all instances will have a property called votingAge even though the value of votingAge is going to be same. All the million person instances can refer to same votingAge method if that method is define in prototype. This will save a lot of memory.

function Person(dob){
  this.dob = dob;
}
Person.prototype.votingAge = 21;

The modified solutions will save memory if a lot of objects are created. However notice that now it will a bit longer for JavaScript engine to look for votingAge method. Previously JavaScript engine would have looked for property named votingAge inside the person object and would have found it. Now the engine will not find votingAge property inside the person object. Then engine will look for person.prototype and will search for votingAge property there. It means, in the modified code engine will find votingAge method in the second hop instead of first hop.

Bringing inheritance using prototype property

Currently Person is defined like this.

function Person(dob){
  this.dob = dob;
}
Person.prototype.votingAge = 21;

If Developer Object wants to extend Person then all that needs to be done is this.

function Developer (dob, skills) {
 this. skills = skills || '';
 this.dob = dob;
}
Developer.prototype = new Person();

Now Developer instance will have access to votingAge method. This is much better. Now there is no code duplication between Developer and Person.

However notice that looking for votingAge method from a Developer instance will take an extra hop.

  • JavaScript engine will first look for votingAge property in the Developer instance object.
  • Next engine will look for votingAge property in its prototype property of Developer instance which is an instance of Person. votingAge method is not declared in the Person instance.
  • Next engine will look for votingAge property in the prototype of Person instance and this method would be found.

Since only the methods that are common to both Developer and Person are present in the Person.prototype there is nothing to be gained by looking for methods in the Person instance. Next implementation will be removing the middle man.

Remove the middle man

Here is the revised implementation of Developer function.

function Developer (dob, skills) {
 this.skills = skills || '';
 this.dob = dob;
}
Developer.prototype = Person.prototype;

In the above case Developer.prototype directly refers to Person.prototype. This will reduce the number of hops needed to get to method votingAge by one compared to previous case.

However there is a problem. If Developer changes the common property then instances of person will see the change. Here is an example.

Developer.prototype.votingAge = 18;
var developer = new Developer('02/02/1970', 'JavaScript');
developer.votingAge; //=> 18

var person = new Person();
person.votingAge; //=> 18. Notice that votingAge for Person has changed from 21 to 18

In order to solve this problem Developer.prototype should point to an empty object. And that empty object should refer to Person.prototype .

Solving the problem by adding an empty object

Here is revised implementation for Developer object.

function Developer(dob, skills) {
  this.dob = dob;
  this.skills = skills;
}
var F = function(){};
F.prototype = Person.prototype;
Developer.prototype = new F();

Let’s test this code.

Developer.prototype.votingAge = 18;
var developer = new Developer('02/02/1970', 'JavaScript');
developer.votingAge; //=> 18

var person = new Person();
person.votingAge; //=> 21

As you can see with the introduction of empty object, Developer instance have votingAge of 18 while Person intances have votingAge of 21.

Accessing super

If child wants to access super object then that should be allowed. That can be accomplished like this.

function Person(dob){
 this.dob = dob;
}
Person.prototype.votingAge = 21;

function Developer(dob, skills) {
  this.dob = dob;
  this.skills = skills;
}
var F = function(){};
F.prototype = Person.prototype;
Developer.prototype = new F();
Developer.prototype.__super = Person.prototype;
Developer.prototype.votingAge = 18;

Capturing it as a pattern

The whole thing can be captured in a helper method that would make it simple to create inheritance.

var extend = function(parent, child){
  var F = function(){};
  F.prototype = parent.prototype;
  child.prototype = new F();
  child.prototype.__super = parent.prototype;
};

Pure prototypal inheritance

A simpler form of pure prototypal inheritance can be structured like this.

if (typeof Object.create !== 'function') {
    Object.create = function (o) {
        function F() {}
        F.prototype = o;
        return new F();
    };
}

Before adding the create method to object, I checked if this method already exists or not. That is important because Object.create is part of ECMAScript 5 and slowly more and more browsers will start adding that method natively to JavaScript.

You can see that Object.create takes only one parameter. This method does not necessarily create a parent child relationship . But it can be a very good tool in converting an object literal to a function.

return false considered harmful in live

Checkout following jQuery code written with jQuery.1.4.2. What do you think will happen when first link is clicked.

$('a:first').live('click', function(){
  log('clicked once');
  return false;
});
$('a:first').live('click', function(){
  log('clicked twice');
  return false;
});

I was expecting that I would see both the messages. However jQuery only invokes the very first message.

return false does two things. It stops the default behavior which is go and fetch the link mentioned in the href of the anchor tags. Also it stops the event from bubbling up. Since live method relies on event bubbling, it makes sense that second message does not appear.

Fix is simple. Just block the default action but let the event bubble up.

$('a:first').live('click', function(e){
  log('clicked once');
  e.preventDefault();
});
$('a:first').live('click', function(e){
  log('clicked twice');
  e.preventDefault();
});

Simplest jQuery slideshow code explanation

Jonathan Snook wrote a blog titled Simplest jQuery SlideShow. Checkout the demo page. The full JavaScript code in its entirety is given below. If you understand this code then you don’t need to read rest of the article.

$(function(){
    $('.fadein img:gt(0)').hide();
    setInterval(function(){
      $('.fadein :first-child').fadeOut()
         .next('img').fadeIn()
         .end().appendTo('.fadein');},
      3000);
});

appendTo removes and attaches elements

In order to understand what’s going on above, I am constructing a simple test page. Here is the html markup.

<div id='container'>
  <div class='lab'>This is div1 </div>
  <div class='lab'>This is div2 </div>
</div>

Open this page in browser and execute following command in firebug.

$('.lab:first').appendTo('#container');

Run the above command 5/6 times to see its effect. Every single time you run JavaScript the order is changing.

The order of div elements with class lab is changing because if a jQuery element is already part of document and that element is being added somewhere else then jQuery will do cut and paste and not copy and paste . Again elements that already exist in the document get plucked out of document and then they are inserted somewhere else in the document.

Back to the original problem

In the original code the very first image is being plucked out of document and that image is being added to set again. In simpler terms this is what is happening. Initially the order is like this.

Image1
Image2
Image3

After the code is executed the order becomes this.

Image2
Image3
Image1

After the code is executed again then the order becomes this.

Image3
Image1
Image2

After the code is executed again then the order becomes this.

Image1
Image2
Image3

And this cycle continues forever.

How jQuery selects elements using Sizzle

jQuery’s motto is to select something and do something with it. As jQuery users, we provide the selection criteria and then we get busy with doing something with the result. This is a good thing. jQuery provides extremely simple API for selecting elements. If you are selecting ids then just prefix the name with ‘#’. If you are selecting a class then prefix it with ‘.’.

However it is important to understand what goes on behind the scene for many reasons. And one of the important reasons is the performance of Rich Client. As more and more web pages use more and more jQuery code, understanding of how jQuery selects elements will speed up the loading of pages.

What is a selector engine

HTML documents are full of html markups. It’s a tree like structure. Ideally speaking all the html documents should be 100% valid xml documents. However if you miss out on closing a div then browsers forgive you ( unless you have asked for strict parsing). Ultimately browser engine sees a well formed xml document. Then the browser engine renders that xml on the browser as a web page.

After a page is rendered then those xml elements are referred as DOM elements.

JavaScript is all about manipulating this tree structure (DOM elements) that browser has created in memory. A good example of manipulating the tree is command like the one give below which would hide the header element. However in order to hide the header tag, jQuery has to get to that DOM element.

jQuery('#header').hide()

The job of a selector engine is to get all the DOM elements matching the criteria provided by a user. There are many JavaScript selector engines in the market. Paul Irish has a nice article about JavaScript CSS Selector Engine timeline .

Sizzle is JavaScript selector engine developed by John Resig and is used internally in jQuery. In this article I will be showing how jQuery in conjunction with Sizzle finds elements.

Browsers help you to get to certain elements

Browsers do provide some helper functions to get to certain types of elements. For example if you want to get DOM element with id header then document.getElementById function can be used like this

document.getElementById('header')

Similarly if you want to collect all the p elements in a document then you could use following code .

document.getElementsByTagName('p')

However if you want something complex like the one given below then browsers were not much help. It was possible to walk up and down the tree however traversing the tree was tricky because of two reasons: a) DOM spec is not very intuitive b) Not all the browsers implemented DOM spec in same way.

jQuery('#header a')

Later selector API came out.

The latest version of all the major browsers support this specification including IE8. However IE7 and IE6 do not support it. This API provides querySelectorAll method which allows one to write complex selector query like document.querySelectorAll("#score>tbody>tr>td:nth-of-type(2)" .

It means that if you are using IE8 or current version of any other modern browser then jQuery code jQuery('#header a') will not even hit Sizzle. That query will be served by a call to querySelectorAll .

However if you are using IE6 or IE7, Sizzle will be invoked for jQuery(‘#header a’). This is one of the reasons why some apps perform much slower on IE6/7 compared to IE8 since a native browser function is much faster then elements retrieval by Sizzle.

Selection process

jQuery has a lot of optimization baked in to make things run faster. In this section I will go through some of the queries and will try to trace the route jQuery follows.

When jQuery sees that the input string is just one word and is looking for an id then jQuery invokes document.getElementById . Straight and simple. Sizzle is not invoked.

$(‘#header a’) on a modern browser

If the browser supports querySelectorAll then querySelectorAll will satisfy this request. Sizzle is not invoked.

$(‘.header a[href!=”hello”]’) on a modern browser

In this case jQuery will try to use querySelectorAll but the result would be an exception (atleast on firefox). The browser will throw an exception because the querySelectorAll method does not support certain selection criteria. In this case when browser throws an exception, jQuery will pass on the request to Sizzle. Sizzle not only supports css 3 selector but it goes above and beyond that.

$(‘.header a’) on IE6/7

On IE6/7 querySelectorAll is not available so jQuery will pass on this request to Sizzle. Let’s see a little bit in detail how Sizzle will go about handling this case.

Sizzle gets the selector string ‘.header a’. It splits the string into two parts and stores in variable called parts.

parts = ['.header', 'a']

Next step is the one which sets Sizzle apart from other selector engines. Instead of first looking for elements with class header and then going down, Sizzle starts with the outer most selector string. As per this presentation from Paul Irish YUI3 and NWMatcher also go right to left.

So in this case Sizzle starts looking for all a elements in the document. Sizzle invokes the method find. Inside the find method Sizzle attempts to find out what kind of pattern this string matches. In this case Sizzle is dealing with string a .

Here is snippet of code from Sizzle.find .

match: {
     ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
     CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
     NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,
     ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
     TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,
     CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,
     POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,
     PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
},

One by one Sizzle will go through all the match definitions. In this case since a is a valid tag, a match will be found for TAG. Next following function will be called.

TAG: function(match, context){
     return context.getElementsByTagName(match[1]);
}

Now result consists of all a elements.

Next task is to find if each of these elements has a parent element matching .header. In order to test that a call will be made to method dirCheck. In short this is what the call looks like.

dir = 'parentNode';
cur = ".header"
checkSet = [ a www.neeraj.name, a www.google.com ] // object representation

dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML )

dirCheck method returns whether each element of checkSet passed the test. After that a call is made to method preFilter. In this method the key code is below

if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n]/g, " ").indexOf(match) >= 0) )

For our example this is what is being checked

" header ".indexOf(" header ")

This operation is repeated for all the elements on the checkSet. Elements not matching the criteria are rejected.

More methods in Sizzle

if you dig more into Sizzle code you would see functions defined as +, > and ~ . Also you will see methods like

enabled: function(elem) {
          return elem.disabled === false && elem.type !== "hidden";
    },
disabled: function(elem) {
          return elem.disabled === true;
     },
checked: function(elem) {
          return elem.checked === true;
     },
selected: function(elem) {
          elem.parentNode.selectedIndex;
          return elem.selected === true;
     },
parent: function(elem) {
          return !!elem.firstChild;
     },
empty: function(elem) {
          return !elem.firstChild;
     },
has: function(elem, i, match) {
          return !!Sizzle( match[3], elem ).length;
     },
header: function(elem) {
          return /h\d/i.test( elem.nodeName );
     },
text: function(elem) {
          return "text" === elem.type;
     },
radio: function(elem) {
          return "radio" === elem.type;
     },
checkbox: function(elem) {
          return "checkbox" === elem.type;
     },
file: function(elem) {
          return "file" === elem.type;
     },
password: function(elem) {
          return "password" === elem.type;
     },
submit: function(elem) {
          return "submit" === elem.type;
     },
image: function(elem) {
          return "image" === elem.type;
     },
reset: function(elem) {
          return "reset" === elem.type;
     },
button: function(elem) {
          return "button" === elem.type || elem.nodeName.toLowerCase() === "button";
     },
input: function(elem) {
          return /input|select|textarea|button/i.test(elem.nodeName);
     }
},

first: function(elem, i) {
          return i === 0;
     },
last: function(elem, i, match, array) {
          return i === array.length - 1;
     },
even: function(elem, i) {
          return i % 2 === 0;
     },
odd: function(elem, i) {
          return i % 2 === 1;
     },
lt: function(elem, i, match) {
          return i < match[3] - 0;
     },
gt: function(elem, i, match) {
          return i > match[3] - 0;
     },
nth: function(elem, i, match) {
          return match[3] - 0 === i;
     },
eq: function(elem, i, match) {
          return match[3] - 0 === i;
     }

I use all these methods almost daily and it was good to see how these methods are actually implemented.

Performance Implications

Now that I have little more understanding of how Sizzle works, I can better optimize my selector queries. Here are two selectors doing the same thing.

$('p.about_me .employment');

$('.about_me  p.employment');

Since Sizzle goes from right to left, in the first case Sizzle will pick up all the elements with the class employment and then Sizzle will try to filter that list. In the second case Sizzle will pick up only the p elements with class employment and then it will filter the list. In the second case the right most selection criteria is more specific and it will bring better performance.

So the rule with Sizzle is to go more specific on right hand side and to go less specific on left hand side. Here is another example.

$('.container :disabled');

$('.container input:disabled');

The second query will perform better because the right side query is more specific.

Understanding jQuery effects queue

Recently I tried following code in jQuery and it did not work.

$('#lab')
  .animate({height: '200px'})
  .hide();

If I pass a parameter to hide then it would start working.

$('#lab')
  .animate({height: '200px'})
  .hide(1);

As it turns out I did not have proper understanding of how effects work in jQuery.

animate method uses a queue inside. This is the queue to which all the pending activities are added.

$('#lab').animate({height: '200px'}).animate({width: '200px'});

In the above code element is being animated twice. However the second animation will not start until the first animation is done. While the first animation is happening the second animation is added to a queue. Name of this default queue is fx. This is the queue to which jQuery adds all the pending activities while one activity is in progress. You can inquire an element about how many pending activities are there in the queue.

$('#lab')
  .animate({height: '200px'})
  .animate({width: '200px'})
  .animate({width: '800px'})
  .queue(function(){ console.log( $(this).queue('fx').length); $(this).dequeue(); })
  .animate({width: '800px'})
  .queue(function(){ console.log( $(this).queue('fx').length);$(this).dequeue(); }) ;

In the above code, twice the current queue is being asked to list number of pending activities. First time the number of pending activities is 3 and the second time it is 1.

Method show and hide also accepts duration. If a duration is passed then that operation is added to the queue. If duration is not passed or if the duration is zero then that operation is not added to queue.

$('#lab').hide(); // this action is not added to fx queue


$('#lab').hide(0); // this action is not added to fx queue


$('#lab').hide(1); // this action is added to fx queue

Coming back to the original question

When show or hide method is invoked without any duration then those actions are not added to queue.

$('#lab')
  .animate({height: '200px'})
  .hide();

In the above code since hide method is not added to queue, both the animate and the hide method are executed simultaneously. Hence the end result is that element is not hidden.

It could be fixed in a number of ways. One way would be to pass a duration to hide method.

$('#lab')
  .animate({height: '200px'})
  .hide(1);

Another way to fix it would be to pass hiding action as a callback function to animate method.

$('#lab')
  .animate({height: '200px'}, function(){
   $(this).hide();
  }
);

Another way would be to explicitly put hide method in a queue.

$('#lab')
  .animate({height: '200px'})
  .queue(function(){
    $(this).hide();
  })

Since hide method is not added to queue by default, in this case I have explicitly put the hide method to the queue.

Note that inside a queue method you must explicitly call dequeue for the next activity from the queue to be picked up.

$('#lab')
    .animate({height: '200px'})
    .queue(function(){
      $(this).hide().dequeue();
    })
    .animate({width: '200px'})

In the above code if dequeue is not called then second animation will never take place.

Also note that methods like fadeTo, fadeIn, fadeOut, slideDown, slideUp and animate are ,by default, added to default queue.

Turning off all animations

If for some reason you don’t want animation then just set $.fx.off = true.

$.fx.off = true;
$('#lab')
   .animate({height: '200px'}, function(){
     $(this).hide();
   });

Above code is telling jQuery to turn off all animations and that would result in the element hiding in an instant.

jQuery edge delegate method has arrived

One of the issues with live method is that live method first searches through all the elements then throws away the result.

$('p').live('click', function({})

In the above case jQuery does nothing with the selected p elements. Since the result does not really matter, it is a good idea to remove such codes from the document ready callbacks list.

So instead of doing this

$(function(){
  $('p').live('click', function({})
})

just do this

$('p').live('click', function({})

Going a step further

John just landed this commit which adds delegate method .

Html markup

<div id='lab'>
  <p>p inside lab</p>
</div>
<p>p outside lab</p>

If you want to track all the clicks on p then you could write like this.

$(document).delegate('p','click', function(){
  log('p was clicked');
});

However if you only want to track clicks on ‘p’ which are inside the id lab then you can write like this.

$('#lab').delegate('p','click', function(){
  log('p was clicked');
});

Note this functionality is in jQuery edge and is not available in jQuery 1.4.1. So you will have to get jQuery code from github to play with it.

If you are interested in the jQuery.live vs jQuery.fn.live discussion then follow this thread .

jQuery show method edge case

Here is a simple case of invoking show method on a hidden element.

<style>
  p { display: inline; }
  #hello p { display: none;}
</style>

<div id='container'>
  <div  id='hello'>
    Hello World
    <p>this is p inside hello</p>
  </div>
</div>

jQuery code.

$('p').show();

You can see the result here . Notice that when p is shown then display property of p is inline which is what it should be. All is well.

Now I’ll change the css a little bit and will try the same code again. New css is .

<style>
  #container p { display: inline; }
  #hello p { display: none;}
</style>

See the result here . Notice that display property of p is block instead of inline .

Where did jQuery go wrong?

jQuery did not do anything wrong. It is just being a bit lazy. I’ll explain.

Since the element was hidden when jQuery was asked to display it, jQuery had no idea where the element should have display property inline or block. So jQuery attempts to find out the display property of the element by asking browser what the display property should be.

jQuery first finds out the nodeName of the element. In this case value would be P. Then jQuery adds a P to body and then asks browser what is the display property of this newly added element. Whatever is the return value jQuery applies that value to the element that was asked to be shown.

In the first experiment, css style ` p { display: inline; }`said that all p elements are inline. So when jQuery added a new p element to body and asked browser for the display property, browser replied ‘inline’ and ‘inline’ was applied to the element. All was good.

In the second case, I changed the stylesheet #container p { display: inline; } to have only p elements under id hello to have inline property. So when jQuery added a p element to body and asked for display type, browser correctly replied as ‘block’.

So what’s the fix.

Find the parent element (#hello) of the element in question ( p in this case) . jQuery should add a new p element to the #hello and then jQuery would get the right display property.

jQuery fadeTo method fades even the hidden elements

Following code has been tested with jQuery 1.4.1 . Code demo links are the end of the blog .

fadeTo method of jQuery ,strangely, fades event the hidden elements.

Here is html markup.

<style> #hello p { display: none;}</style>
<div id='hello'>
  <p>this is p inside hello</p>
</div>
<p>This is p outside hello</p>

Since the first p is hidden, you will see only one p element in the browser. Now execute following jQuery code.

$('p').fadeTo('slow', 0.5');

You will see both the p elements.

jQuery goes out of its way to make sure that hidden elements are visible. Here is fadeTo method.

fadeTo: function( speed, to, callback ) {
	return this.filter(":hidden").css("opacity", 0).show().end()
				.animate({opacity: to}, speed, callback);
}

Also notice that for a hidden element fadeTo operation starts with opacity of zero, while other elements will go down towards zero.

Checkout the same demo in slow motion and notice that while the first p element emerges out of hiding, the other p element is slowing fading. This might cause unwanted effect . So watch out for this one.

Order of format matters in respond_to block

This is a standard Rails code. I am using Rails 2.3.5 .

class UsersController < ApplicationController
  def index
    @users = User.all
    respond_to do |format|
      format.html
      format.js  { render :json => @users }
    end
  end
end

Accidentally in one of my controllers the order of formats got reversed. The altered code looks like this.

class UsersController < ApplicationController
  def index
    @users = User.all
    respond_to do |format|
      format.js  { render :json => @users }
      format.html
    end
  end
end

I thought order of format declaration does not matter. I was wrong.

> curl -I http://localhost:3000/users
HTTP/1.1 200 OK
Connection: close
Date: Mon, 25 Jan 2010 22:32:16 GMT
ETag: "d751713988987e9331980363e24189ce"
Content-Type: text/javascript; charset=utf-8
X-Runtime: 62
Content-Length: 2
Cache-Control: private, max-age=0, must-revalidate

Notice the the Content-Type of in the response header is text/javascript in stead of text/html .

Well I guess the order of format matters. I hope it is fixed in Rails 3.

How animate really works in jQuery

jQuery has animate method which is just awesome. Today I looked into jQuery source code to see exactly how animate works.

I will take a simple case of animating a div from height of 34 to 100.

Here is test case.

$(function(){
  $('#lab').css({background: 'yellow', height: '34px', margin: '10px'});

  $('a').click(function(){
    $('#lab').animate({height: '100'});
      return false;
    });
});

Html markup is .

<a href=''>click me</a>
<div id='lab'>Hello World</div>

Inside the animate for each property an fx object is created.

jQuery.each( prop, function( name, val ) {
  var e = new jQuery.fx( self, opt, name );
}

Calling new on jQuery.fx returns a JavaScript object instance.

fx: function( elem, options, prop ) {
	this.options = options;
	this.elem = elem;
	this.prop = prop;

	if ( !options.orig ) {
		options.orig = {};
	}
}

Next in the animate method is a call to e.custom .

start = 34;
end = 100;
unit = 'px';
e.custom( start, end, unit );

start, end and unit values are gleaned from the current state of div.

Here is custom method .

custom: function( from, to, unit ) {
	this.startTime = now();
	this.start = from;
	this.end = to;
	this.unit = unit || this.unit || "px";
	this.now = this.start;
	this.pos = this.state = 0;

	var self = this;
	function t( gotoEnd ) {
		return self.step(gotoEnd);
	}

	t.elem = this.elem;

	if ( t() && jQuery.timers.push(t) && !timerId ) {
		timerId = setInterval(jQuery.fx.tick, 13);
	}
},

As you can see every 13 milliseconds a call to step method is made.

step method is where real calculation is done. Here is the code.

step: function( gotoEnd ) {
  var t = now();
  var n = t - this.startTime;
  this.state = n / this.options.duration;
  pos = jQuery.easing['swing'](this.state, n, 0, 1, this.options.duration);
  this.now = this.start + ((this.end - this.start) * this.pos);
  this.update();
}

this.startTime is the time when the call to animate was invoked. The step method is called periodically from custom method. So the value of t is constantly changing. Based on the value of t, value of n will change. Some of the values of n I got was 1, 39, 69, 376 and 387.

While invoking animate method I did not specify a speed. jQuery picked up the default speed of 400. In this case the value of this.options.duration is 400. The value of state would change in each run and it would something along the line of 0.0025, 0.09, 0.265, 0.915 and 0.945 .

If you don’t know what easing is then you should read this article by Brandon Aaron. Since I did not specify easing option, jQuery will pickup swing easing .

In order to get the value of next position this easing algorithm needs state, n and duration. When all of it was supplied then pos would be derived. The value of pos over the period of animation would change and it would be something like 0, 0.019853157161528467, 0.04927244144387716, 0.9730426794137726, 0.9973960708808632.

Based on the value of pos value of now is derived. And then update method is called to update the screen.

update method has following code that invokes _default method.

jQuery.fx.step._default)( this )

_default method has following code which finally updates the element.

fx.elem.style[ fx.prop ] = Math.max(0, fx.now);

fx.now value was set in the custom method and here that value was actually applied to the element.

You will have much better understanding of how animate works if you look at the source code. I just wanted to know at a high level what’s going on and these are my findings.

Handling JSON parsing natively in jQuery 1.4 and what changed from jQuery 1.3

With the popularity of JavaScript JSON has become very very popular. JSON which stands for JavaScript Object Notation is a popular way to send and receive data between browser and server.

jQuery makes it extremely easy to deal with JSON data. In the below example server sends a success message to browser. The JSON data looks like this.

{ 'success': 'record was successfully updated' }

The jQuery code to handle JSON data looks like this.

$.ajax({
   type: "GET",
   url: "test.js",
   dataType: "json",
   success: function(json){
     $('#result').text(json.success);
   }
 });

It all looks good and the code works with jQuery 1.3 .

However if you upgrade to jQuery 1.4 then above code will stop working. Why? jQuery 1.4 does strict JSON parsing using native parse method and any malformed JSON structure will be rejected.

How jQuery 1.3 parses JSON structure

jQuery 1.3 uses JavaScript’s eval to evaluate incoming JSON structure. Open firebug and type following example.

s = " { 'success' :  'record was updated' } "
result = eval('(' + s + ')');
console.log(result);

You will get a valid output.

Note that all valid JSON structure is also valid JavaScript code so eval converts a valid JSON structure into a JavaScript object. However non JSON structure can also be converted into JavaScript object.

JSON specification says that all string values must use double quotes. Single quotes are not allowed. What it means is that following JSON structures are not valid JSON.

{ 'foo' : 'bar' }
{ foo: 'bar' }
{ foo: "bar" }
{ "foo" : 'bar' }

Even though above strings are not valid JSON if you eval them they will produce a valid JavaScript object. Since jQuery 1.3 uses eval on strings to convert JSON structure to JavaScript object all the above mentioned examples work.

However they will not work if you upgrade to jQuery 1.4 .

jQuery 1.4 uses native JSON parsing

Using eval to convert JSON into JavaScript object has a few issue. First is the security. It is possible that eval could execute some malicious code. Secondly it is not as fast as native parse methods made available by browsers. However browsers adhere to JSON spec and they will not parse malformed JSON structures. Open firebug and try following code to see how native browser methods do not parse malformed JSON structure. Here is the link to the announcement of Firefox support for native JSON parsing . John Resig mentioned the need for jQuery to have native JSON parsing support here .

s = " { 'success' :  'record was updated' } "
result = eval('(' + s + ')');
console.log(result); /* returns valid JavaScript object */

result2 = window.JSON.parse(s);
console.log(result2); /* throws error */

As you can see a string which was successfully parsed by eval failed by window.JSON.parse . It might or might not fail in chrome. More on that later. Since jQuery 1.4 will rely on browsers parsing the JSON structure malformed JSON structures will fail.

In order to ensure that JSON is correctly parsed by the browsers, jQuery does some code cleanup to make sure that you are not trying to pass something malicious. You will not be able to test this thing directly using firebug but if you make an AJAX request and from server if you send response the you can verify the following code.

Following JSON structure will be correctly parsed in jQuery 1.3 . However the same JSON structure will fail in jQuery 1.4 . Why? Because of dangling open bracket [ .

' { "error" : "record was updated" }'

jQuery 1.4 has following code that does some data cleanup to get around the security issue with JSON parsing before sending that data to browser for parsing. Here is a snippet of the code.

// Make sure the incoming data is actual JSON

// Logic borrowed from http://json.org/json2.js

if (/^[\],:{}\s]*$/.test(data.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, "@")
	.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, "]")
	.replace(/(?:^|:|,)(?:\s*\[)+/g, "")))

Not all browsers parse JSON same way

Earlier I mentioned that following JSON structure will not be correctly parsed by browsers.

” { 'a':1 } ”

All browsers will fail to parse above JSON structure except chrome . Look at this blog titled Cross Browser JSON parsing to get more insight into this issue.

I have malformed JSON and I want to use jQuery 1.4

If you have malformed JSON and you want to use jQuery 1.4 then you should send the datatype as text and then convert the returned JSON structure using eval. Here is one way you can do that.

$.ajax({url: "/url",
  dataType: "text",
  success: function(data) {
    json = eval("(" + data + ")");
    // do something with json

  }
});

Ben Alman suggested another way in the comment section .

/* this should be the very first JavaScript inclusion file */
<script type=”text/javascript” language=”javascript”>window.JSON = null;</script>

jQuery attempts to parse JSON natively. However if native JSON parsing is not available then it falls back to eval. Here by setting window.JSON to null browser is faking that it does not have support for native JSON parsing.

Here are the two commits which made most of the changes in the way parsing is done.

Use JSONLint if you want to play with various strings to see which one is valid JSON and which one is not.

How jQuery 1.4 fixed rest of live methods

If you look at jQuery 1.3 documentation for live method you will notice that the live method is not supported for following events: blur, focus, mouseenter, mouseleave, change and submit .

jQuery 1.4 fixed them all.

In this article I am going to discuss how jQuery brought support for these methods in jQuery. If you want a little background on what is live method and how it works then you should read this article which I wrote sometime back.

focus and blur events

IE and other browsers do not bubble focus and blur events. And that is in compliance with the w3c events model. As per the spec focus event and blur event do not bubble.

However the spec also mentions two additional events called DOMFocusIn and DOMFocusOut. As per the spec these two events should bubble. Firefox and other browsers implemented DOMFocusIn/DOMFocusOut . However IE implemented focusin and focusout and IE made sure that these two events do bubble up.

jQuery team decided to pick shorter name and introduced two new events: focusin and focusout. These two events bubble and hence they can be used with live method. This commit makes focusin/focusout work with live method. Here is code snippet.

if ( document.addEventListener ) {
	jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
		jQuery.event.special[ fix ] = {
			setup: function() {
				this.addEventListener( orig, handler, true );
			},
			teardown: function() {
				this.removeEventListener( orig, handler, true );
			}
		};

		function handler( e ) {
			e = jQuery.event.fix( e );
			e.type = fix;
			return jQuery.event.handle.call( this, e );
		}
	});
}

Once again make sure that you are using focusin/focusout instead of focus/blur when used with live .

mouseenter and mouseleave events

mouseenter and mouseleave events do not bubble in IE. However mouseover and mouseout do bubble in IE. If you are not sure of what the difference is between mouseenter and mouseover then watch this excellent screencast by Ben.

The fix that was applied to map for focusin can be replicated here to fix mousetner and mouseleave issue. This is the commit that fixed mouseenter and mouseleave issue with live method.

jQuery.each({
	mouseenter: "mouseover",
	mouseleave: "mouseout"
}, function( orig, fix ) {
	jQuery.event.special[ orig ] = {
		setup: function( data ) {
			jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
		},
		teardown: function( data ) {
			jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
		}
	};
});

Event detection

Two more events are left to be handled: submit and change. Before jQuery applies fix for these two events, jQuery needs a way to detect if a browser allows submit and change events to bubble or not. jQuery team does not favor browser sniffing. So how to go about detecting event support without browser sniffing.

Juriy Zaytsev posted an excellent blog titled Detecting event support without browser sniffing . Here is the a short and concise way he proposes to find out if an event is supported by a browser.

var isEventSupported = (function(){
    var TAGNAMES = {
      'select':'input','change':'input',
      'submit':'form','reset':'form',
      'error':'img','load':'img','abort':'img'
    }
    function isEventSupported(eventName) {
      var el = document.createElement(TAGNAMES[eventName] || 'div');
      eventName = 'on' + eventName;
      var isSupported = (eventName in el);
      if (!isSupported) {
        el.setAttribute(eventName, 'return;');
        isSupported = typeof el[eventName] == 'function';
      }
      el = null;
      return isSupported;
    }
    return isEventSupported;
  })();

In the comments section John Resig mentioned that this technique can also be used to find out if an event bubbles or not.

John committed following code to jQuery.

var eventSupported = function( eventName ) {
	var el = document.createElement("div");
	eventName = "on" + eventName;

	var isSupported = (eventName in el);
	if ( !isSupported ) {
		el.setAttribute(eventName, "return;");
		isSupported = typeof el[eventName] === "function";
	}
	el = null;

	return isSupported;
};

jQuery.support.submitBubbles = eventSupported("submit");
jQuery.support.changeBubbles = eventSupported("change");

Next task is to actually make a change event or a submit event bubble if ,based on above code, it is determined that browse is not bubbling those events .

Making change event bubble

On a form a person can change so many things including checkbox, radio button, select menu, textarea etc. jQuery team implemented a full blown change tracker which would detect every single change on the form and will act accordingly.

Radio button, checkbox and select changes will be detected via change event. Here is the code.

click: function( e ) {
	var elem = e.target, type = elem.type;

	if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
		return testChange.call( this, e );
	}
},

In order to detect changes on other fields like input field, textarea etc keydown event would be used. Here it the code.

keydown: function( e ) {
	var elem = e.target, type = elem.type;

	if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
		(e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
		type === "select-multiple" ) {
		return testChange.call( this, e );
	}
},

IE has a proprietary event called beforeactivate which gets fired before any change happens. This event is used to store the existing value of the field. After the click or keydown event the changed value is captured. Then these two values are matched to see if really a change has happened. Here is code for detecting the match.

function testChange( e ) {
		var elem = e.target, data, val;

		if ( !formElems.test( elem.nodeName ) || elem.readOnly ) {
			return;
		}

		data = jQuery.data( elem, "_change_data" );
		val = getVal(elem);

		if ( val === data ) {
			return;
		}

		// the current data will be also retrieved by beforeactivate

		if ( e.type !== "focusout" || elem.type !== "radio" ) {
			jQuery.data( elem, "_change_data", val );
		}

		if ( elem.type !== "select" && (data != null || val) ) {
			e.type = "change";
			return jQuery.event.trigger( e, arguments[1], this );
		}
}

Here is the commit that fixed this issue.

jQuery.event.special.change = {
	filters: {
		focusout: testChange,

		click: function( e ) {
			var elem = e.target, type = elem.type;

			if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
				return testChange.call( this, e );
			}
		},

		// Change has to be called before submit

		// Keydown will be called before keypress, which is used in submit-event delegation

		keydown: function( e ) {
			var elem = e.target, type = elem.type;

			if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
				(e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
				type === "select-multiple" ) {
				return testChange.call( this, e );
			}
		},

		// Beforeactivate happens also before the previous element is blurred

		// with this event you can't trigger a change event, but you can store

		// information/focus[in] is not needed anymore

		beforeactivate: function( e ) {
			var elem = e.target;

			if ( elem.nodeName.toLowerCase() === "input" && elem.type === "radio" ) {
				jQuery.data( elem, "_change_data", getVal(elem) );
			}
		}
	},
	setup: function( data, namespaces, fn ) {
		for ( var type in changeFilters ) {
			jQuery.event.add( this, type + ".specialChange." + fn.guid, changeFilters[type] );
		}

		return formElems.test( this.nodeName );
	},
	remove: function( namespaces, fn ) {
		for ( var type in changeFilters ) {
			jQuery.event.remove( this, type + ".specialChange" + (fn ? "."+fn.guid : ""), changeFilters[type] );
		}

		return formElems.test( this.nodeName );
	}
};

var changeFilters = jQuery.event.special.change.filters;

}

Making submit event bubble

In order to detect submission of a form, one needs to watch for click event on a submit button or an image button. Additionally one can hit ‘enter’ using keyboard and can submit the form. All of these need be tracked.

jQuery.event.special.submit = {
	setup: function( data, namespaces, fn ) {
		if ( this.nodeName.toLowerCase() !== "form" ) {
			jQuery.event.add(this, "click.specialSubmit." + fn.guid, function( e ) {
				var elem = e.target, type = elem.type;

				if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
					return trigger( "submit", this, arguments );
				}
			});

			jQuery.event.add(this, "keypress.specialSubmit." + fn.guid, function( e ) {
				var elem = e.target, type = elem.type;

				if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
					return trigger( "submit", this, arguments );
				}
			});
		}
	},

	remove: function( namespaces, fn ) {
		jQuery.event.remove( this, "click.specialSubmit" + (fn ? "."+fn.guid : "") );
		jQuery.event.remove( this, "keypress.specialSubmit" + (fn ? "."+fn.guid : "") );
	}
};

As you can see if a submit button or an image is clicked inside a form the submit event is triggered. Additionally keypress event is monitored and if the keyCode is 13 then the form is submitted.

live method is just pure awesome. It is great to see last few wrinkles getting sorted out. A big Thank You to Justin Meyer of JavaScriptMVC who submitted most of the patch for fixing this vexing issue.

Hidden feature of jQuery - calling a method on a jQuery collection

I was going through the Adding keyboard navigation and noticed that Remi replaced this code

$('.coda-slider-wrapper ul a.current').parent().next().find('a').click();

with this code

var direction = 'next';
$('.coda-slider-wrapper ul a.current').parent()[direction]().find('a').click();

I had never seen anything like that. In the above mentioned article, Remi used next and prev methods. However I wanted to know all the options I could pass since this feature is not very documented.

Snippet from jQuery source code

Here is code from jQuery that makes that above method work.

jQuery.each({
	parent: function(elem){return elem.parentNode;},
	parents: function(elem){return jQuery.dir(elem,"parentNode");},
	next: function(elem){return jQuery.nth(elem,2,"nextSibling");},
	prev: function(elem){return jQuery.nth(elem,2,"previousSibling");},
	nextAll: function(elem){return jQuery.dir(elem,"nextSibling");},
	prevAll: function(elem){return jQuery.dir(elem,"previousSibling");},
	siblings: function(elem){return jQuery.sibling(elem.parentNode.firstChild,elem);},
	children: function(elem){return jQuery.sibling(elem.firstChild);},
	contents: function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes);}
}, function(name, fn){
	jQuery.fn[ name ] = function( selector ) {
		var ret = jQuery.map( this, fn );

		if ( selector && typeof selector == "string" )
			ret = jQuery.multiFilter( selector, ret );

		return this.pushStack( jQuery.unique( ret ), name, selector );
	};
});

As you can see, a variety of selectors can be passed to jQueryCollection[].

If you want to give a try, any jQuery enabled site should perform all of the below mentioned code without any problem.

var a = $('a:first');
var log = console.log;

log(a['parent']());
log(a['parents']());
log(a['next']());
log(a['prev']());
log(a['nextAll']());
log(a['prevAll']());
log(a['siblings']());
log(a['children']());
log(a['contents']());

Use end more often in jQuery while building DOM elements

I want to create following markup dynamically using jQuery.

<div>
  <p>
    This is p
  </p>
</div>

Following jQuery code will do the work.

$(document).ready(function() {
  var div = $('<div></div>');
  var p = $('<p></p>').text('this is p')
                      .appendTo(div);

  $('body').append(div);
});

A better way to accomplish the same is presented below.

$('<div></div>')
  .append('<p></p>')
    .find('p')
    .text('this is p')
    .end()
  .appendTo('body');

Using .end() you can go back one level. And you can use .end() any number of times to get out of a deeply nested tag.

$('<div></div>')
  .append('<p></p>')
    .find('p')
    .append('<span></span>')
      .find('span')
      .text('this is span')
      .end()
    .end()
  .appendTo('body');

JavaScript Basics Quiz

Let’s look at some JavaScript questions.

Question 1

What’s the output.

x = 90;
function f(){
  console.log(x);
  var x = 100;
}
f();

Answer 1

The result is undefined . In JavaScript a variable exists in the scope of a function and that variable can be defined anywhere in the function. To find out more about lexical scope read here and here .

Question 2

Go to prototype homepage open firebug and execute following code.

var a = ['a','b','c'];
var result = '\n';
for (i in a){
  result += 'index: '+ i + ' value:' + a[i] + '\n';
}

Now go to jQuery homepage and execute the same code. Notice the difference in output. Why the difference?

Answer 2

Prototype adds additional methods to Array using Array.prototype . Those methods show up when you iterate through them. If you want to ignore methods added through Array.prototype then use this code.

var a = ['a','b','c'];
var result = '\n';
for (i in a){
  if (a.hasOwnProperty(i))
    result += 'index: '+ i + ' value:' + a[i] + '\n';
}

Question 3

In order to find if an element with id foo is present, one can do

if ($('#foo').length > 0)
  console.log('id foo is present');

How can you make the conditional statement shorter.

Answer 3

In JavaScript following items evaluate to false in a conditional statement: undefined, null, false, empty string, NaN, 0

if ($('#foo'))
  console.log('id foo is present');

Question 4

What is the output in this case. Notice that function bar is defined after the return statement.

function foo(){
  console.log(z);
  console.log(bar());
  return true;

  function bar(){
    return 'this is bar';
  };

  var z = 'zzz';
};

foo();

Answer 4

Output is

undefined
this is bar
true

Question 5

What’s output in this case.

function logit(n){console.log(n);}

for(i=1;i<5;i++){
 setInterval(function(){logit(i)},2000);
}

Answer 5

The result would be output 5 5 5 5 and all the four output will appear together in one shot. Then after 2 seconds another set of similar data would appear. This would continue forever.

Question is why do I see the output in one single shot and why do I see value 5 for all four cases.

Browsers execute JavaScript in a single thread. While that thread is busy executing ‘for loop’ the thread makes note of additional instructions like setInterval. Since the thread is already running ‘for loop’, the same thread can’t run setInterval. So the thread finishes the ‘for loop’ and then looks up additional tasks to be performed. It find setInterval task to be waiting. It executes the function. While it is executing the function ,by virtue of closure, the value of i is 5. Hence you see ` 5 5 5 5` and you see all that in one single shot.

Correct implementation would be

function logit(n){console.log(n);}

var counter = 0;
var timer = setInterval(function() {
	logit(counter);
	counter++
	if (counter == 5) {
		clearTimeout(timer);
	}
},
2000);

Above code would print 0 1 2 3 4 at an interval of 2 seconds.

Question 6

What’s the output in this case.

flight = { status: 'arrived'}
console.log(typeof(flight.status));
console.log(typeof(flight.toString));
console.log(flight.hasOwnProperty('status'));
console.log(flight.hasOwnProperty('toString'));

Answer 6

string
function
true
false

Question 7

What’s output in this case.

function Person(name) { this.name = name;}
Person.prototype.welcome = function(){ return 'welcome ' + this.name}

p = new Person('John');

console.log(p.welcome.call(p));

o = {name: 'Mary'}

console.log(Person.prototype.welcome.call(o));

Answer 7

welcome John
welcome Mary

Question 8

JavaScript has Math library which can be used like this

Math.max(6,7,8) // result is 8

If I provide an array with certain values then how would you find the max value for that array.

a = [1,2,3];

Answer 8

This answer builds up on the answer provided in #7 .

You can try this but it will fail.

Math.max(a) //output is NaN

You can try this but it will fail too.

Math.max.call(Math,a); // output is NaN

This will work

Math.max.apply(Math,a); //output is 3

apply method works because it accepts an array as the argument. call method passes the individual params to the called method directly and hence it does not work. You can read more about JavaScript apply and call methods here .

How live method works in jQuery. Why it does not work in some cases. When to use livequery.

Following code has been tested with jQuery 1.3.2 version .

All the JavaScript code mentioned in this blog should be tried on firebug.

The super popular live method was added to jQuery 1.3 . It works just great. Except when it does not work. As per the documentation this method does not work in following cases: blur, focus, mouseenter, mouseleave, change, submit .

How binding events work in jQuery

$('a').click(function(){
  console.log('clicked');
});

In above case click event is bound to all the links in the document. jQuery stores such binding information as data attribute of the bound element. This is how I can access the list of all functions bound to an element.

$('a').data('events');// Object click=Object

If a new link is dynamically added then that new link will not get this click behavior. Tosolve this problem I can use live method.

Trying out live event

$('a').live('click',function(){
  console.log('clicked');
});

If I add a new a tag dynamically then that tag will automatically get the new click behavior. That’s great.

Just like the previous section, now I am going to find the events bound to a element. However when I execute following code I get undefined .

$('a').data('events')); //undefined

Why is that. In the previous section I showed that all the events bound to an element are stored as the data attribute of that element. Well, live is different. live events are not bound to the element directly. They are bound to the top level ‘document’. I can verify this by trying out this code

jQuery.data(document, 'events').live; //Object

How does live method work

live methods do not set anything on elements directly. All the event handlers are set at the document level. It means that in order for live methods to work, event bubbling is required. If you don’t know what event bubbling is then read her . It also means that event should not be stopped while it is propagating to document. If event propagation is stopped then event handlers bound at the document level will never know about that event and live method will fail.

The strategy to let someone else deal with the event is called event delegation. You can read more about event delegation here .

When live method is called then a binding is done at the document level. Loosely translated this is what is basically happening.

$(document).bind('click', function(event){
  var $target = $(event.target);
  if($target.is('p')){
    console.log('p was clicked');
  }
});

As you can see when a click on p event bubbles all the way to the top then that event is captured by document and necessary action is taken if the target element matches.

It is clear that if the click event is stopped before it reaches document then live method will not work. I will show you an example.

<div id='parent'>
 Languages
 <p>Java</p>
 <p>Javascript</p>
</div>
$('p').live('click',function(e){
  console.log('p was clicked');
});

If I click on Java or Javascript I get a message on console. live is working great. Now I’ll stop the event propagation when event reaches to div.

$('p').live('click',function(e){
  console.log('p was clicked');
});

$('#parent').click(function(e){
  console.log('stopping propagation');
  e.stopPropagation();
});

Now you will notice that live is no more working.

live does not work when event bubbling is not supported

In the previous section I showed that when event does not bubble up to document then live fails. It means that all the events that do not bubble will not work. Which means that events like blur, focus, mouseenter, mouseleave, change and submit which do bubble in IE will not work in IE. However note that these events will continue to work in Firefox.

<select id='lab1a' name="sweets" multiple="multiple">
<option>Chocolate</option>
<option selected="selected">Candy</option>
<option>Taffy</option>
<option selected="selected">Caramel</option>
<option>Fudge</option>
<option>Cookie</option>
</select>
<div id='lab1b' style='color:red;'></div>
$("#lab1a").live('change',function () {
  var str = "";
  $("select option:selected").each(function () {
    str += $(this).text() + " ";
  });
  $("#lab1b").text(str);
});

Above code will work in firefox but it will not work in IE.

Here is an example of an event that does not work in IE: onchange event.

DOM models suggest that onchange event should bubble . However msdn documentation clearly says that onchange event does not bubble .

Make all the live method problems go away

To recap live method will not work in following cases:

  • live method works on event propagation, if an event is stopped while it is bubbling then live will not work.
  • IE does not support bubbling for certain events. live method on those events will not work in IE.

There is a way to get around to both the problems.

Brandon Aaron developed livequery plugin which was finally merged into jQuery as live method. livequery plugin solves both the problems listed above and the code works in IE too.

First step is to include this plugin

<script src="http://github.com/brandonaaron/livequery/raw/master/jquery.livequery.js" type="text/javascript"></script>

Now try this code.

$('p').livequery('click',function(e){
  alert('p was clicked');
});

$('#parent').click(function(e){
  alert('stopping progpagation');
  e.stopPropagation();
});

$("#lab1a").livequery('change',function () {
  var str = "";
  $("select option:selected").each(function () {
    str += $(this).text() + " ";
  });
  $("#lab1b").text(str);
});
<select id='lab1a' name="sweets" multiple="multiple">
  <option>Chocolate</option>
  <option selected="selected">Candy</option>
  <option>Taffy</option>
  <option selected="selected">Caramel</option>
  <option>Fudge</option>
  <option>Cookie</option>
</select>
<div id='lab1b' style='color:red;'></div>
<div id='parent'>
 Languages
 <p>Java</p>
 <p>Javascript</p>
</div>

If I click on ‘Java’ or ‘Javascript’ I will get proper response even though event propagation is being stopped. Also even though change event does not bubble in IE, above code works in IE.

livequery works because livequery ,unlike live, method does not do binding at the document level. livequery does binding at the element level. You can find that out by running following code.

$('p').data('events');

Above code will produce result if I am using livequery. Above code will not produce any result if I am using live method.

The key piece of code in the plugin that makes all this work is

// Create a timeout to check the queue and actually run the Live Queries

$.livequery.timeout = setTimeout($.livequery.checkQueue, 20);

Every 20 milliseconds livequery runs all the bindings defined in livequery and then binds the matched element with the event.

By understanding the internals of how live and livequery are implemented, now you can choose to use livequery in certain cases where live will not work. Also it helps to understand how live actually works.

Live method finds elements and then throws it away. Not very efficient.

A typical use of live method is something like this.

$('p').live('click',function(e){
  console.log('p was clicked');
});

As it has already been discussed a live method registers events at document level.

However when $('p').live(...) is evaluated then jQuery first goes and finds all the p elements. And then what does it do with those elements. Nothing. That’s right. jQuery throws away all those p elements which were just found without using them. What a waste.

If your application has a lot of live methods and this might slow down the performance of the application.

A better solution would have been to design an API like this one:

$.live('p', 'click', function(){..});

jQuery is flexible and I can create my own live method but it will add to the confusion. Another solution would be to make the call to live method without first finding all those p element. Here is how it can be done.

var myDocument = $(document);
myDocument.selector = 'p';
myDocument.live('click', function(){
  console.log('p was clicked');
});

In the above case no element will be selected only to be thrown away. This is much better.

Seeing is believing

In the previous section, I showed how live method can be made to work without first selecting the elements. However a friend of mine asked me if I could conclusively prove that in the real live method a find is actually done. And in my solution a find call is not done.

Here I am showing you the overriding find method. In this method I am overriding the original find method. I will put a log message before passing the find method to the original method.

(function() {
  var originalFindMethod = jQuery.fn.find;
  jQuery.fn.find = function() {
    console.log('find was called');
    originalFindMethod.apply(this, arguments);
  };
})();

$(document).ready(function() {
  $('p').live('click', function() {
    console.log('p was clicked');
  });
});

In the above case you will get message on firebug console confirming that find is indeed invoked when live method is called.

Here is revised version of live. Try this one.

(function() {
  var originalFindMethod = jQuery.fn.find;
  jQuery.fn.find = function() {
    console.log('find was called');
    originalFindMethod.apply(this, arguments);
  };
})();

$(document).ready(function() {
  var myDocument = $(document);
  myDocument.selector = 'p';
  myDocument.live('click', function() {
    console.log('p was clicked');
  });
});

Above version does not print ‘find was called’.

Encapsulation in JavaScript

JavaScript does not allow you to define a method as public or private. This is a limitation users need to get around to, because in real life you don’t want to expose all methods as public method.

Here is a simple implementation of the case where you want to verify input code.

function verifycode(code){
  console.log(code.length);
  return code.length == 4 ? true : false;
}

function info(code){
  if (verifycode(code)){
    console.log(code + ' is valid');
  } else {
    console.log(code + ' is wrong');
  }
}

info('abcd');
info('rty');

In the above implementation anyone can call the method verifycode. Not good. Here is one way to fix this problem.

var Lab = Lab || {};
Lab = (function() {
	var verifycode = function(code) {
		console.log(code.length);
		return code.length == 4 ? true: false;
	}
	return {
		info: function(code) {
			if (verifycode(code)) {
				console.log(code + ' is valid');
			} else {
				console.log(code + ' is wrong');
			}
		}
	}
})();

Lab.info('abcd');
Lab.info('rty');
Lab.verifycode('abcd'); //verifycode is private

Another way to solve the same problem would be to create a constructor function. Here is an implementation.

function Lab(code) {
        this.code = code;
	var verifycode = function() {
		return code.length == 4 ? true: false;
	};
	this.info = function() {
		if (verifycode()) {
			console.log(code + ' is valid');
		} else {
			console.log(code + ' is wrong');
		}
	}
}
(new Lab('abcd')).info();

Here is another way to solve the same problem. In this case I have moved all the public methods to prototype.

function Lab(code) {
	this.code = code;
	this.verifycode = function() {
		l = code.length;
		return l == 4 ? true: false;
	};
}

Lab.prototype.info = function() {
	if (this.verifycode()) {
		console.log(this.code + ' is valid');
	} else {
		console.log(this.code + ' is wrong');
	}
};

(new Lab('abcd')).info();

Integrating JavaScriptLint with mvim and getting rid of annoying warnings

I use JavaScriptLint along with JavaScriptLint.vim on mvim to catch any JavaScript syntax error or missing semicolons. It works great except in cases when I am chaining methods like this.

var select_col1 = $('<select></select>')
  .addClass('ram_drop_down')
  .addClass('ram_drop_down_col1')
  .attr('name','adv_search['+random_num+'_row][col1]')
  .attr('id',random_num+'_ram_drop_down_col1');

In such cases JavaScriptLint had warnings for me.

unexpected end of line. It is ambiguous whether these lines are part of the same statment.

JavaScriptLint wants me to put the dot at the end of the line and not at the beginning of the line. Well, I like having dots at the beginning of lines and I wanted to turn off such warning.

JavaScriptLint comes with a default config file. I copied the config file to a personal directory and disabled the warning.

before: +ambiguous_newline
after: -ambiguous_newline

Also I had to comment out +process jsl-test.js at the very bottom. Now tell your plugin to to use this configuration file rather than the default one. Add the following line to your vimrc file.

let jslint_command_options = '-conf "/Users/neeraj/vim/plugin/jslint/jsl.custom.conf" -nofilelisting -nocontext -nosummary -nologo -process'

This is the vim settings I use and it has been configured to take care of it. Just go to vimrc.local and change the path to your config file. Also don’t forget to remove " at the beginning of the line to uncomment it.