3

Consider this HTML:

<p>Click me</p>

I would like to write an object with a click handler for each p, but run into the problem that my click handler function could not be found.

This code does not work:

(function(){
    var self = this;

    $("p").each(function(){
        $(this).click(self.myFunction);
    });

    self.myFunction = function(){ alert("myFunction"); }
})();​

When I wrap the click handler assignment in a function it does work:

(function(){
    var self = this;

    $("p").each(function(){
        $(this).click(function(){ self.myFunction(); });
    });

    self.myFunction = function(){ alert("myFunction"); }
})();

Question: Why doesn't $(this).click(self.myFunction) work, but $(this).click(function(){ self.myFunction(); }) does?


Edit: The following code does work:

$("p").click(myFunction);
function myFunction(){ alert("myFunction"); }

Shouldn't this fail as well?


P.S. I got my object working without the need to wrap the function by moving the location of the function:

(function(){
    var self = this;

    self.myFunction = function(){ alert("myFunction"); }

    $("p").each(function(){
        $(this).click(self.myFunction);
    });
})();

I guess the problem is parser related.

Jasper de Vries
  • 19,370
  • 6
  • 64
  • 102
  • 1
    You need to understand javascript code parsing and evaluation order. See this: http://stackoverflow.com/questions/3887408/javascript-function-declaration-and-evaluation-order/3887590#3887590 – slebetman Sep 07 '12 at 09:36
  • @slebetman +1 for you answer to the other question. Thanks. – Jasper de Vries Sep 08 '12 at 08:34

2 Answers2

3

In this:

(function(){
    var self = this;

    $("p").each(function(){
        $(this).click(self.myFunction);
    });

    self.myFunction = function(){ alert("myFunction"); }
})();?

The reference is evaluated immediately, and since nothing has been placed in self yet, it fails.

Here:

(function(){
    var self = this;

    $("p").each(function(){
        $(this).click(function(){ self.myFunction(); });
    });

    self.myFunction = function(){ alert("myFunction"); }
})();

The reference is evaluated when the click actually happens, much after self.myfunction is assigned to.

This is in fact not a problem, and an intentional design feature.

In this example:

$("p").click(myFunction);
function myFunction(){ alert("myFunction"); }

The function name is being hoisted to the top of the scope. Since there is nothing dynamic about this function definition (meaning it's not being assigned to an object dynamically), it's available all throughout this scope, from top to bottom.

Functions fill many gaps in JavaScript.

They act as lambdas, modules, methods, functions and probably more that I can't think of right now.

Lucas Green
  • 3,951
  • 22
  • 27
  • 1
    Good explanation, will vote up tomorrow as I have used up all my votes for the day :) This is an additional resource to understand these kinds of things, (by John Resig!): http://ejohn.org/apps/learn – Asciiom Sep 07 '12 at 08:49
  • Thanks for explaining. I need to keep this in mind when designing objects. – Jasper de Vries Sep 07 '12 at 09:09
0

I think you already figured out your problem. At the moment you attach the handlers, self.myFunction isn't defined, so no even handler is attached.

But when you wrap the call like function(){ self.myFunction(); }, then self.myFunction is called at the moment the handler is called, not when it's attached.

MaxArt
  • 22,200
  • 10
  • 82
  • 81