Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change context in $.each()

I'm trying to change the context for jQuery's $.each method. What did I miss?

$.each.call(this, [1,2,3], function(){
    console.log(this); // expecting to see the window object
});

var foo = { bar: 1 };
$.each.call(foo, [1,2,3], function(){
    console.log(this); // expecting to see the foo object
});

http://jsfiddle.net/53jhrbh5/

like image 902
filur Avatar asked Feb 05 '15 15:02

filur


3 Answers

$.each uses call and apply internally to set the right this value in the callback, something like callback.apply(obj[i]), so it uses the array for the this value, and calling the method with call won't change that.

It works something like this

function each(obj, callback, args) {
    var value, i = 0,
        length   = obj.length,
        isArray  = isArraylike(obj);

    if (args) {
        if (isArray) {
            for (; i < length; i++) {
                value = callback.apply(obj[i], args);
            }
        } else {
            for (i in obj) {
                value = callback.apply(obj[i], args);
            }
        }
    }
    return obj;
}

See how it calls the callback, passing in each value from the passed array or object as the this value, and that means you can't change it by calling the $.each method differently, as it's this value has nothing to do with the this value of the callback function, that's being set by jQuery.

You could $.proxy it, or bind() it, but the easy way is just to use a variable

var self = this;

$.each(arr, function() {
     console.log( self );
});
like image 191
adeneo Avatar answered Oct 24 '22 16:10

adeneo


There are several ways to do this

1) Reference window from outside

var self = this;
$.each.call(this, [1,2,3], function(){
    console.log(self); // expecting to see the window object
});

2) Bind the function to a particular scope

$.each.call(this, [1,2,3], function(){
    console.log(this); // expecting to see the window object
}.bind(this));

3) Use ES6 arrow function which binds to current context (Can't use in most browsers without some 6->5 conversion)

$.each.call(this, [1,2,3], () => {
   console.log(this); // expecting to see the window object
});

4) Just reference window directly

$.each.call(this, [1,2,3], () => {
   console.log(window); // expecting to see the window object
});
like image 5
David Rice Avatar answered Oct 24 '22 14:10

David Rice


Just use Function.bind on the callback to specify what context you want the function to run in.

$.each([1,2,3], (function(){
    console.log(this); // expecting to see the window object
}).bind(this));

Internally jQuery uses ThisBinding modifiers like apply, call. So, this will always be a Number, unless you specify the context of the callback to be run.

like image 3
Amit Joki Avatar answered Oct 24 '22 16:10

Amit Joki