简体   繁体   中英

jQuery closure: How to get a value from a function click

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 !

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.

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);

}());

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.

eg

// 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM