简体   繁体   中英

How to pass the 'callbacks' array argument to an anonymous function?

I have a member function in the object which gets the array of callback functions and the name of the event for which this function is set:

...
setHandlesByList: function (list) {
    for (var i in list) {
        var self = this;
        $(document).on(list[i].name, function (e) {
            list[i].callBack.call(self,e)
        });
    };
},
...

Somewhere in the child objects I have a call to this function of the parent object:

...
initClass: function () {
    this.setHandlesByList([
     { name: 'configChecked', callBack: onConfigChecked },
     { name: 'configExpired', callBack: onConfigExpired },
    ]);
},
onConfigChecked: function() {
    // some code
},
onConfigExpired: function() {
    // some code
},
....

but something goes wrong - for all events the handler is the last set callback function...

Try the following:

setHandlesByList: function (list) {
    for ( var i = 0; i < list.length; i++ ) {
        addCallback(list[i].name, list[i].callback);
    }
    function addCallback(on, name, callback) {
        $(document).on(name, function(e) { callback.call(on, e); });
    }
},

There is a problem with your scoping, because the value of i eventually ends up being the last value of i when your callbacks are evaluated.

Also note that you could use list.forEach .

Each event handler function you create in this code:

setHandlesByList: function (list) {
    for (var i in list) {
    var self = this;
    $(document).on(list[i].name, function (e) {
        list[i].callBack.call(self,e)
        });
    };
},

...has an enduring reference to list and i , not copies of them as of when the function is created. Since i ends up being the last property enumerated, all handlers end up referring to the same list entry.

Instead, create a builder function to create the callback (sorry, I can't recreate the indentation style you use, I've just used a fairly standard one) :

setHandlesByList: function (list) {
    var self = this;

    for (var i in list) {
        $(document).on(list[i].name, buildHandler(list[i]));
    };

    function buildHandler(entry) {
        return function (e) {
            entry.callBack.call(self,e)
        };
    }
},

Now, the function created closes over entry , the argument to the buildHandler call, rather than over list and i . Since entry (the argument) doesn't change, the handler works.

Note also that I've moved the var self = this; out of the loop, as it didn't vary from iteration to iteration and so had no business being in the loop.


Side note: You've said that the function receives an array . If so, for-in (with no safeguards) is not the correct way to loop through the entries in that array. More: Myths and realities of for..in

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