Online Book Reader

Home Category

AJAX In Action [296]

By Root 3875 0
a function getAge(). Note here that we’re defining a function inside another function and that the inner function uses the local variable createTime, belonging to the scope of the outer function. By doing this, and nothing else, we have in fact created a closure. If we define a robot and ask it how old it is once the page has loaded,

var robbie=new Robot();

window.onload=function(){

alert(robbie.getAge());

}

then it works and gives us a value of around 10–50 milliseconds, the difference between the script first executing and the page loading up. Although we have declared createTime as being local to the constructor function scope, it cannot be garbage-collected so long as Robbie the robot is still referenced, because it has been bound up in a closure.

The closure works only if the inner function is created inside the outer one. If we refactor my code to predefine the getAge function and share it between all robot instances, like so

function Robot(){

var createTime=new Date();

this.getAge=roboAge;

}

function roboAge(){

var now=new Date();

var age=now-createTime;

return age;

};

then the closure isn’t created, and we get an error message telling me that createTime is not defined. Licensed to jonathan zheng

616

APPENDIX B

JavaScript for object-oriented programmers

Closures are very easy to create and far too easy to create accidentally, because closures bind otherwise local variables and keep them from the garbage collector. If DOM nodes, for example, get caught up in this way, then inadvertently created closures can lead to significant memory leaks over time.

The most common situation in which to create closures is when binding an event-handler callback function to the source of the event. As we discussed in section B.3.4, the callback is invoked with a context and set of arguments that is sometimes not as useful as it might be. We presented a pattern for attaching additional references (the Model object) to the DOM element that generates the event, allowing us to retrieve the Model via the DOM element. Closures provide an alternative way of doing this, as illustrated here: myObj.prototype.createView=function(){

...

this.titleBar=document.createElement("div");

var modelObj=this;

this.titleBar.onclick=function(){

fooEventHandler.call(modelObj);

}

}

The anonymous onclick handler function that we define makes a reference to the locally declared variable modelObj, and so a closure is created around it, allowing modelObj to be resolved when the function is invoked. Note that closures will resolve only local variables, not those referenced through this.

We use this approach in the ContentLoader object that we introduced in chapter 2, because the onreadystatechange callback provided in Internet Explorer returns the window object as the function context. Since window is defined globally, we have no way of knowing which ContentLoader’s readyState has changed, unless we pass a reference to the relevant loader object through a closure. My recommendation to the average Ajax programmer is to avoid closures if there is an alternative. If you use the prototype to assign functions to your custom object types, then you don’t duplicate the functions and you don’t create closures. Let’s rewrite our Robot class to follow this advice:

function Robot(){

this.createTime=new Date();

}

Robot.prototype.getAge=function(){

var now=new Date();

var age=now-this.createTime;

return age;

};

Licensed to jonathan zheng

Resources

617

The function getAge() is defined only once, and, because it is attached to the prototype, it is accessible to every Robot that we create. Closures have their uses, but we’d consider them an advanced topic. If you do want to explore closures in greater depth, then Jim Ley’s article, listed in the Resources section, is a good place to start.

B.4 Conclusions

We’ve taken you through some of the stranger and more interesting features of the JavaScript language in this appendix, with two purposes in mind. The first was to show the expressive power of

Return Main Page Previous Page Next Page

®Online Book Reader