Adarsh Konchady
Adarsh Konchady

Reputation: 2737

Calling a function passed to a JQuery handler

function test() {
  var str = 'adarsh';

  // f1(); - This gives an error.
  $('body').click(function f1() {
    console.log(str);
  });
}

test();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

I want to know why the above snippet gives an error when I try to access f1() inside the function test.

What is the function f1 scoped to?
I know it is not the window because I cannot access window.f1 after executing the above snippet.

Note: I know I can declare function f1 first and then pass the reference to it in the click function. However I want to know what is the point of naming 'anonymous' functions in such contexts if we cannot access them anywhere through that name.

Upvotes: 3

Views: 57

Answers (4)

guest271314
guest271314

Reputation: 1

Calling a function passed to a JQuery handler

You can use jQuery._data() to access and call the event handler of click, f1, outside of .click()

function test() {
  var str = "adarsh";
  
  // f1(); - This gives an error.
  $("body").click(function f1() {
    console.log(str);
  });

  var ref = $._data(document.body, "events")["click"][0];
  
  console.log(ref.handler, ref.handler.name);

  ref.handler()
}

test();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<body>click</body>

Upvotes: 0

Quentin
Quentin

Reputation: 943108

A function declaration will:

  • Create a variable with the same name as the function in the current scope.

A named function expression (which is what you have here) will:

  • Create a variable with the same name as the function inside the scope of that function (which is useful for calling itself recursively).
  • Evaluate as the function

So there are two ways you can access the function you created with the named function expression:

  • Put something on the left hand side of the expression. In this case you are already doing that by passing it to click(), so the click function can do something with it
  • Call it by name from inside itself

There are no further references to it in the scope of test.

However I want to know what is the point of naming 'anonymous' functions in such contexts if we cannot access them anywhere through that name.

As I said, the variable is useful for calling it recursively.

The name (which is different to the variable) is also useful as it shows up in debuggers. It is a lot easier to deal with a stacktrace consisting of a dozen useful names than one which is just a dozen repetitions of (anonymous function).

Upvotes: 5

georg
georg

Reputation: 214949

The BindingIdentifier in a FunctionExpression can be referenced from inside the FunctionExpression's FunctionBody to allow the function to call itself recursively. However, unlike in a FunctionDeclaration, the BindingIdentifier in a FunctionExpression cannot be referenced from and does not affect the scope enclosing the FunctionExpression. @@ http://www.ecma-international.org/ecma-262/6.0/#sec-function-definitions-runtime-semantics-evaluation

In other words, when you have a function expression like function someName() {...} (not to confuse with a function declaration) the name is bound inside the function, not in the containing scope.

fun = function someName() {
  
  alert(someName);  // works
  
};  

alert(typeof someName); // doesn't work

fun();

The purpose of giving names to function expressions is to have meaningful stack traces.

Upvotes: 4

Rory McCrossan
Rory McCrossan

Reputation: 337560

What is the function 'f1' scoped to?

It's not scoped to anything. The reference of the function is provided to the handler only, so there is nothing else defined which points to that function. If you want to define the function so that it can be called in multiple places you would need to change your logic to something like this:

function test() {
    var str = 'adarsh';
    $('body').click(function() { // < note the anonymous function here
        f1(str);
    });
}

function f1(str) {
    console.log(str);
}

test();
f1('foo bar');

Upvotes: 3

Related Questions