views:

227

answers:

5

If I have a chunk of code like this:

.hover(
     function () {
      hoverState($("#navbar a").index(this),1);
     },
     function () {
      hoverState($("#navbar a").index(this),-1);
});

Is there any way to get rid of the anonymous functions and just say:

.hover(
    hoverState($("#navbar a").index(this),1),
    hoverState($("#navbar a").index(this),-1);
);
+9  A: 

The reason for the anonymous function is to defer the call to hoverState until the hover event happens. Without some function reference there, you end up calling hoverState and the result of the function call becomes the parameter to the hover method, which is certainly not what you want. The alternative would be to have a named function, but that's really no better and, in some ways, actually worse.

tvanfosson
Makes a lot more sense now, thanks.
Rob
+8  A: 

No, because otherwise your call:

hoverState($("#navbar a").index(this),1)

would evaluate at the same time as the call to the hover function itself. Since Javascript supports closures and first-class functions, you could make a wrapper function:

function wrapper(position){
    function _f(){
        hoverState($("#navbar a").index(this), position);
    }
    return _f;
}

And then use:

.hover(
    wrapper(1),
    wrapper(-1),
)

But the gains of such an approach are questionable.

oggy
This is a great explanation. Not only do I understand how to do it, I now realize that it's definitely not what I want to do. Thanks!
Rob
+1  A: 

My answer can seem stupid but here goes... you can use simple functions :}

function hoverStateProxy1() {
        hoverState($("#navbar a").index(this),1);
}


function hoverStateProxy2() {
        hoverState($("#navbar a").index(this),-1);
}

.hover(hoverStateProxy1, hoverStateProxy2);

As long as you passing reference to function you are OK. It can be both anonymous or not.

Sergej Andrejev
I don't think this method would work, because you aren't passing the "this" value to the functions.
fudgey
I actually thought about doing something like that, but like fudgey said, it won't work because of the "this" value. Moreover, you appear to have defined a function, redefined it, and called it twice ;)
Rob
It would work fine, the this would be the element moused over/off
redsquare
I'm kinda lazy to check this but I think this will work as expected
Sergej Andrejev
A: 

You could use JavaScript's "Apply" Function. Here is an example taken from the Prototype.js framework (bind implementation, though it should probably be renamed if not being used from within the framework).

EDIT: Corrected, see This Post

if (!Object.bind) {
    Function.prototype.bind= function(owner) {
        var that= this;
        var args= Array.prototype.slice.call(arguments, 1);
        return function() {
            return that.apply(owner,
                args.length===0? arguments : arguments.length===0? args :
                args.concat(Array.prototype.slice.call(arguments, 0))
            );
        };
    };
}

Usage:

.hover(
    hoverState.bind(this,$("#navbar a").index(this),1),
    hoverState.bind(this,$("#navbar a").index(this),-1)
);
Dereleased
function.bind will be a standard part of ECMAScript 5, so I'd recommend it. However the implementation above is incomplete; see the end of http://stackoverflow.com/questions/748941/setattribute-onclick-and-cross-browser-compatability#749253 for another stand-alone implementation. (Also, there appear to be a couple of spurious open brackets in that example.)
bobince
Ah, I was a bit hasty when I made that post it seems. Updated.
Dereleased
+2  A: 

There's a way to do something like this, with the jLambda plugin.

// Without plugin:
$('.foo').click(
            function() {
                $(this).hide();
                $('p').show();
                $('a').width(20);
            });

// With plugin:
$('.foo').click($l.hide().$('p').show().$('a').width(20));
mahemoff