Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I've been writing most of my javascript applications in an OO style close to what I would use for most other languages. However, this means that most callbacks need to have a reference to an object, and I generally handle that by using $.proxy (or dojo.hitch, or whatever the framework's tool for this is) to be sure that the callbacks are operating in the context of my object, rather than the tag they were attached to.

Very quickly, this seems to lead to using proxied calls for almost everything, and can look like I'm fighting against the tool, particularly if the tool is jQuery.

Do you have a policy on how to handle javascript function binding in your work? Do you try fit your design to how the tool binds it's functions, or do you force the bindings to work according to your design?

share|improve this question
1  
Can you precise why you don't generally simply use closures or inline functions ? –  dystroy Apr 18 '13 at 15:06
    
Neither scales past a certain level of complexity, and they both present the same issue, where jQuery blows away the current object scope. Stuffing a bunch of variables just so that I have access to them in the closure seems like a worse solution. –  Dan Monego Apr 18 '13 at 15:48
6  
I know people often try to refute this fact, but the developer of JavaScript, Brendan Eich himself claimed "I was recruited to Netscape with the promise of “doing Scheme” in the browser." which is functional and based entirely on using lexical closures. Using JavaScript as an OO language is going against the grain, regardless of what many people may believe. JQuery embraces this fact, which is part of why it's so successful. –  Jimmy Hoffa Apr 18 '13 at 15:50
1  
A code example of what you're trying to do would be helpful - it sounds like what you want is something like the module pattern, but you might be trying to do it using OO methods. –  Tacroy Apr 18 '13 at 15:58
2  
@Esailija jQuery is a monadic api with internal continuation pumps, you can say that it's OO but there's nothing OO about that style or implementation. the DOM has nothing to do with javascript, that's strictly an implementation of the browser. Also, in javascript closures have a type similar to lambda-mu, that is not typical of non-functional languages. Furthermore, no, most languages do not have arbitrary depth lexically scoped closures, sorry to burst your bubble.. –  Jimmy Hoffa Apr 18 '13 at 23:02

3 Answers 3

up vote 4 down vote accepted

Well the alternatives to function binding are a lot worse, instead of a simple $.proxy call, the popular alternative is to type this every time

var self = this;
$().click( function(e) {
    self.doit(e);
});

Compared to

$().click($.proxy(this.doit, this));

I have an active feature request for jQuery where this would be possible:

$().click(this);

This is what the standard event listener api supports:

elem.addEventListener("click", this);

The method .handleEvent is then called on this when the event occurs, with proper context. The element as this is just useless because it can be always attained from event.currentTarget.

So it's not a code smell in that you could replace it with something simpler or better.

share|improve this answer

If you need the context for multiple functions, I agree with Esailija's solution. It's common and simple.

If you only need it once, this is also available:

$().click( function(e) {
    this.do_something();
}.bind(this) );

If do_something takes no arguments (so it'll discard the e) and the anonymous function would only call it, I believe this also works:

$().click( this.do_something.bind(this) );
share|improve this answer

If the function to which you're binding is simple (no return value, no arguments), $.proxy seems like the simplest option (plus, it has other functionality). $.proxy is also essential when the proxy function's context is not the location from which it is being called, e.g. $.proxy(Class1.function1, Class1).

However, since you mentioned that you've "been writing most of my javascript applications in an OO style close to what I would use for most other languages", I highly recommend TypeScript and its lambda syntax. I've provided a relevant example below, but first, an intro:

CoffeeScript, Google Dart, and other more mature languages have similar goals, but I'm not familiar with those--what you use will depend on the development tools and languages with which you're most comfortable. If you use Microsoft languages and development tools, TypeScript is probably the best option (JetBrains IDEs have strong TypeScript support, as well).

I recently started implementing TypeScript in my projects because it brings object orientation to JavaScript and works well with .NET server-side languages (the open-source TypeLite makes it easy to automatically generate TypeScript interfaces from .NET classes: http://type.litesolutions.net/). Although TypeScript is a Microsoft-initiated product, it's an open-source language. For example, JetBrains' WebStorm IDE supports TypeScript more thoroughly than Visual Studio at this point; I use WebStorm along with Visual Studio for that reason.

I just realized that the OO-specific problem with $.proxy is that you can't enforce strongly-typed method arguments and return values. But if you use lambdas in TypeScript (syntax that will be available in ECMAScript 6), you can enforce that without writing all the extra code required in ECMAScript 5. Here's a working TypeScript example:

interface ICallbackData{
Value1: boolean;
Value2: string; 
}

class Manager{
    private _CallbackProxy: (CallbackData: ICallbackData)=>string;
    constructor(){
        this._CallbackProxy = (CallbackData)=>this.CallbackHandler(CallbackData);
    }   
    CallbackHandler(CallbackData: ICallbackData): string{
        if (CallbackData.Value1){
            return CallbackData.Value2;
        }
        return "Other String";
    }

    Value: number;
    PerformActionThenCallback(){
        this.Value += 1;
        this._CallbackProxy(<ICallbackData>{Value1: true, Value2: "Callback String, Value: " + this.Value.toString()});
    }
}

You can see the JavaScript to which that code will compile by plugging it in here: http://www.typescriptlang.org/Playground

TypeScript will be ready for the future of ECMAScript, so you won't have to rewrite or upgrade your code. For example, lambda functions written in TypeScript currently compile similar to what Esailija wrote (the alternative to $.proxy):

var self = this;
$().click( function(e) {
    self.doit(e);
});

It compiles to that because it is trying to be compatible with as many browsers' ECMAScript 5 implementations (it can currently compile to be compatible with ECMAScript 3 or 5; I'm not sure why it doesn't compile using .bind() for ECMAScript 5--that's a different topic). But when ECMAScript 6 is widespread, TypeScript lambdas will compile directly as lambdas without generating all that extra code. For now, though, at least there are robust OO languages that compile to JavaScript and simplify OO requirements, while eliminating the need to wait for ECMAScript 6 and beyond.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.