4

I don't quite understand JS closures and I think it can solve my problem. here it is:

I have something like that :

$(document).ready(function () {
    $("#buttonConfirm").click(function () {
        popup_confirme();
    });
});
function popup_confirme() {
    var r = popup_modal();
}
function popup_modal() {
    var int_val = 0;
    $(".button").click(function () {
        int_val = ($(this).val() == 'yes' ? '1' : '0');
    });
    return int_val;
}

I would like to get my int_val returned by the button click event. I need to get the 'r' value as 0 or 1. I know I should use closures, but I dont know how to do it. Thank you for your expertise !

1
  • 4
    It's not just a case of using closures, it's a case of restructuring your code to use callbacks to cater for the asynchronous nature of waiting for the user to click a button. Which, at ten after midnight, is something I don't have time to write up in more detail. Commented Jun 14, 2013 at 14:07

3 Answers 3

3

You can't do this, it's impossible, for reasons unrelated to closures.

Your not calling the code that sets int_val, you're only defining the code, and saying "when .buttons are clicked, invoke this code". The code will not have been executed at the point you run return int_val, it will be executed at some point in the future when the button is clicked.

This block of code cannot logically work:

// First line run
var int_val = 0;

// Second line run
$(".button").click(function () {
    // This line runs in the future, or maybe never, if the button isn't clicked
    int_val = ($(this).val() == 'yes' ? '1' : '0');
});

// Third line run
return int_val;

If you want to communicate values back out of asynchronous functions, you should use promises:

function popup_modal() {
    var dfd = $.Deferred();

    $(".button").click(function () {
        int_val = ($(this).val() == 'yes' ? '1' : '0');

        // Allow int_val to find its way back to the calling code's `done` handler
        dfd.resolve(int_val);
    });

    return dfd.promise()
}

The calling code will receive a promise object, which it can add callbacks to:

function popup_confirme() {
    var r;
    popup_modal().done(function (int_val) {
      r = int_val;
    }
}

I can't intuit beyond this point what you meant int_val to do up in your calling code.

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you for your answer, but I have to use jQuery 1.4 unfortunately, so I cannot use Deferred Object. It is as you said, I want communicate values back out of asynchronous functions if possible.
Then look into callbacks. You'll have to pass a callback function into your functions, which eventually gets invoked by your event handler.
Yep, It is ok now, I had to restructure the code and now it works.
Yep, It is ok now, I had to restructure the code and now it works.to make it short: var fct_confirm = function(bln_ok){ if(bln_ok) alert('ok'); else alert('ko'); return bln_ok; }; popup_modal( obj_params, fct_confirm);
1

A closure occurs when an inner function references something defined outside it. To illustrate:

function outer() {
    var foo = 1;
    element.click(function () {
        // this function creates a closure on foo.
        alert(foo);
    });
};

What you seem to want done is that your int_val variable be accessible where both popup_modal and popup_confirme can get to it.

Many ways to do it based off your example, but something as simple as this can work:

(function () {

    var int_val = 0;

    var popup_modal = function () {
        int_val = $(this).val() === 'yes' ? 1 : 0;
    };

    var popup_confirme = function () {
        // your original code here doesn't really do anything
        alert(int_val);
    };

    $('.button').click(popup_modal);
    $('#buttonConfirm').click(popup_confirme);

}());

1 Comment

I like the way you referenced popup_modal here.
1

Technically all JavaScript functions are closures as they are objects with a scope chain attached to them. A closure is simply the combination of a function object and a scope (a set of variable bindings).

Scope is actually pretty simple really. Javascript uses lexical scoping which means that function are executed in the variable scope that was in effect when they were defined. Simply put, An outer function cannot read a value from an inner function unless is is specifically returned. An inner function can read all values declared in an outer function.

When most people talking about closures they are actually referring to the act of returning an item from an inner nested function to the outer function in which it has been defined.

e.g

// I am the outer function.
function outer (){

var outerVariable = "I am available to inner functions.";

    // I am an inner function. I was declared in the scope of the outer 
    // function and as such all the variables declared in that scope are 
    // available to me.
    function inner (){

        // This will return => "I am available to inner functions." as we can 
        // read the outer declaration.
        var innerReadValue = outerVariable; 

        // This will be available only to the inner function as it is 
        // not returned.
        var privateVariable = "I am private";

        // This will be available to the outer function as we are returning it 
        // on the next line.
        var publicVariable = "I am available to outer functions";

        // Make publicVariable public. This is what most people refer to 
        // when talking about closures. 
        return publicVariable; 

    }

    // Read the inner functions publicVariable declaration.
    // Returns => "I am available to outer functions"
    var outerReadValue = inner();

}

In your example you are trying to get a value that was declared and not returned on the inner scope. As you should understand by now, this is invisible to the outer function so cannot work.

This can be rewritten as such:

// This is called an Immediately Invoked Function Expression. IIFE, It 
// basically wraps your code in a function hiding all internal declarations
// from the global scope and then invokes it. You don't want to pollute the 
// global scope.
(function(){

    // Declare this outside so all functions can read it.
    var int_val = 0;

    // Declare this outside so all functions can read it.
    var popup_confirm = function(){
        // "int_val" is available here.
        return int_val;
    };

    // Although your function runs automatically, we delay binding until
    // the DOM is ready.
    $(document).ready(function(){

        $("#buttonConfirm").click(function(){
           // Provide feedback. "popup_confirm" is available here
           // since is declared in the outer scope.
           return popup_confirm();
         });

        $(".button").click(function(){
            // Set the value of int_val that has been declared in the outer 
            // scope.
            int_val = $(this).val() === "yes" ? 1 : 0;

        });    
    });

}());

Hopefully this makes it all a little bit more clear to you.

4 Comments

thanks, but I have some constraints bcse of the exisiting code. I need to declare a function popup_confirm() and get its returned value (1 or 0)
No problem, I've updated the example for you. Do you understand the explanation?
Yes I understand but, $(".button").click(function(){} which gives me 1 or 0 is in the popup_confirm function, and then I want get the int_val from this click(function)
Yep, It is ok now, I had to restructure the code and now it works.to make it short: var fct_confirm = function(bln_ok){ if(bln_ok) alert('ok'); else alert('ko'); return bln_ok; }; popup_modal( obj_params, fct_confirm);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.