3

Possible Duplicate:
Why does click event handler fire immediately upon page load?

There is a gap in my understanding of Javascript's function so I have trouble understanding why my event handlers get fired automatically if I define it without an anonymous wrapper.

HTML

<a href="#" id="change-html">Change HTML</a>

Javascript #1

var btn = $('#change-html');
btn.click(bindClick(btn)); // bindClick gets executed right away and only once

function bindClick(source){
    console.log('get here');
}

Javascript #2

var btn = $('#change-html');
btn.click(function(){
    bindClick(btn); // bindClick is only executed on the anchor's click event 
});

function bindClick(source){
    console.log('get here');
}
Community
  • 1
  • 1
Lim H.
  • 9,049
  • 9
  • 43
  • 70
  • `()` after a function reference **calls** the function. Which function do you think is executed first in this example: `foo(bar())`? It's the same case when you bind event handlers :) – Felix Kling Jan 25 '13 at 08:42
  • thanks a lot. Now it's clear. – Lim H. Jan 25 '13 at 08:46

2 Answers2

7

Actually here

btn.click(bindClick(btn)); 

you are just binding the return value of the function to the click event, not the function itself.
Since in javascript you can return a function this would work

var btn = $('#change-html');
btn.click(bindClick(btn));

function bindClick(source){
    return function() {
        console.log('get here');
    }    
}

http://jsfiddle.net/VZ4Gq/

EDIT - is the second function a closure?Yes it might be.Let's lok at this example

var btn = $('#change-html');
btn.click(bindClick(btn));
// global scope
var inside = "i'm outside a closure";
console.log(inside);
function bindClick(source){
    // local scope 
    var inside = "i'm inside a closure";
    return function() {
        console.log(inside);
    }   
}

http://jsfiddle.net/VZ4Gq/1/

when you try this you get logged "i'm outside a closure" first and then when you click on the button you get "i'm inside a closure". this is because you actually created a closure and the ffunction, when it's executo, it's executed in it's original scope, which is inside bindClick()

Nicola Peluchetti
  • 72,169
  • 29
  • 129
  • 186
  • Thank you. I'm still struggling to understand closure. – Lim H. Jan 25 '13 at 08:50
  • Or, even better, modify your `bindClick` function so you don't need the parameter - you already have `this` inside the event handler function to refer to the element that triggered the event, passing it in doesn't really make any sense (it's just an added, unnecessary complication). Then you can just do: `btn.click(bindClick);` – Anthony Grist Jan 25 '13 at 09:04
  • @LimH. this is not a closure, a closure it's a different thing, this just relates to the order of function execution as Felix King clearly explained in a comment. My example just shows you that BindClick is executed before btn.click() and for this reason the return value of BtnClick (which is a function) is assigned as the event handler. – Nicola Peluchetti Jan 25 '13 at 09:07
  • @AnthonyGrist I normally don't use parameter. That's why I'm confused when I happened. – Lim H. Jan 25 '13 at 09:13
  • @NicolaPeluchetti No I understand the execution order mistake. But your syntax is like a closure right? Doesn't it mean you can return the inner function and have it wrapped around inner variables (even though there is none here)? Sorry I'm still quite a noob in JS... – Lim H. Jan 25 '13 at 09:15
  • 1
    @LimH. ok yes that could be a closure, i edited my answer to try to explain closures to you with an example based on your code. – Nicola Peluchetti Jan 25 '13 at 09:23
  • @NicolaPeluchetti that was awesome. Thank you! – Lim H. Jan 25 '13 at 09:29
1

The problem is :

btn.click(bindClick(btn));

It will call the bindClick method. Try to change that line with this and see if the behavior if same with JavaScript#2:

btn.click({param1: btn }, bindClick);

Or more simpler :

btn.click({param1: btn }, $(this));
Iswanto San
  • 17,245
  • 11
  • 56
  • 77