"JavaScript" registering JavaScript Object methods as callbacks

Source: Internet
Author: User
Tags closure ibm developerworks

The registration of callback functions is very common in JavaScript Web programming, for example to attach user interface Event handlers (such as onclick), or to provide a function to handle an XHR response. Registering an object method as a callback function isn't entirely straightforward, but there is a number of approaches That's we can use.

Let's say we ve got a constructor, an object, and a function that registers a callback:

function MyObject(val){    this.val = val;}MyObject.prototype.alertVal = function(){    alert(this.val);}var obj = new MyObject(8);function register(callback){    // some time later...    callback();}

The constructor stores its single argument, and the Alertval () method alerts it. The Simple register () function takes a function and calls it. In a real situation the behaviour here would is much more interesting and this would do for illustration.

Why we don ' t want to just pass obj.alertval to register ()

Object methods is first-class functions in JavaScript and we could pass obj.alertval to register () –but it isn ' t quite w Hat we want. Let's see what happens:

register(obj.alertVal);// inside register(), callback === obj.alertValcallback()// inside MyObject.prototype.alertValalert(this.val);// because callback() was not called on an object,// this === the JavaScript global object and not obj;// this.val is the global variable val, not obj.val

When a function is called as a method in an object (Obj.alertval ()), "This" is bound to the object, it's called on (o BJ). And when a function was called without an object (func ()), the ' this ' is bound to the JavaScript global object (Windows in Web B Rowsers.) When we passed obj.alertval to register () we were passing a reference to the function bound to obj.alertval, but no refere nCE to the object obj.

So, we need-bind our method to the object.

Closure with an anonymous function

In JavaScript, whenever a function is defined within another one a closure are created [JavaScript Closures for Dummies] [J Avascript Closures]. A closure remembers the variable bindings that were in scope when the function is created. These bindings and available whenever the function is called. We can bind our method to our object instance with the following:

register(function(){obj.alertVal()});

Whenever the anonymous function is called, "obj" would be a bound to the value of it had when the function was created. Which is exactly and what we want.

(If We execute the above code outside a function it'll behave differently. No closure would be created, instead, the current value of the global variable "obj" would be used whenever the anonymous Fu Nction is called, not the value at function definition.)

If we want to register a method on the object currently bound to ' this ', we need to take an extra step:

var obj = this;register(function(){obj.alertVal()});

If we don ' t explicitly bind "this" to a named variable (obj) and instead use register(function(){this.alertVal()}) we'll lose our object reference. "This" would be bound to the JavaScript global object whenever the anonymous function is called.

Build a generic closure maker

Instead of building a closure each time we want to register a method as a callback, we could write a utility function to D O It for us. For example:

function bind(toObject, methodName){    return function(){toObject[methodName]()}}

With such a function we can then register our method with:

register(bind(obj, "alertVal"));

Dojo (Dojo.hitch ()) and Prototype (Bind ()) both has such utility functions (that also allow you to provide arguments to P The called, something that we "bind" doesn ' t do.

If we want to register a method of "This", we don ' t need to explicitly bind it (as we do above) before calling "bind" –t He function call does the binding for us. register(bind(this, "alertVal"))works as expected.

Alter The Register function to take the object too

If We changed our register function to:

function register(anObject, methodName){    // some time later...    anObject[methodName]();}

We could register our call with:

register(obj, "alertVal");

Dojo.connect and Yui ' s YAHOO.util.Event.addListener () [Yui Event Utility] [YAHOO.util.Event API docs] Both include this bi Nding style in their API.

Bind the method to the object at construction

We could bind our method to the object (or instance variables as shown here) in the constructor function:

function MyObject(val){    this.alertVal = function(){        alert(val);    }}

We could then registers obj.alertval directly as "Val" is already bound:

obj = new MyObject(8);register(obj.alertVal);

Douglas Crockford writes about this programming style in Private members in JavaScript.

Circular References and memory leaks

Whichever method need to being careful about avoiding circular references when registering event handlers (such a s onclick) on document objects. For example, if we register an object method as a event handler on a element, such that the method was bound to the OBJEC T, and the object had a reference back to the element, then we had a circular reference, and a potential leak (in this CA Se A solution would is to has the object store the element ' s ID rather than store a reference to the element object Itsel F.) Here is some articles that discuss ways to cause memory leaks and ways to avoid them:

    • Memory leak patterns in JavaScript by Abhijeet Bhattacharya and Kiran Shivarama Sundar (IBM developerWorks)
    • Understanding and solving Internet Explorer Leak Patterns by Justin Rogers (Microsoft)
    • JavaScript Closures by Richard Cornford

Http://www.bitstructures.com/2007/11/javascript-method-callbacks.html

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.