Reuben Tanner
Reuben Tanner

Reputation: 5565

Odd $.each behavior

Consider the following examples:

var x = [1, 2, 3];
$.each(x, function(){
    console.log(this);
});

var o1 = {x:1, y:2};
var o2 = {a:1, b:2};
var o3 = {d:1, e:2}
var y = [o1, o2, o3];
$.each(y, function(){
    console.log(this);
});

Both of these work as expected: this refers to the currently referenced object from the collection passed in.

However, the next example is truly odd.

var z = [null];
$.each(z, function(){
    console.log(this);
});

In this example, you'll notice that the window is logged to the console.

Why is this the case?

It is easily remedied by doing more explicit parameterization like so:

$.each(z, function(key, value){
    console.log(value);
}); 

But I'm particularly curious as to why this refers to window in the previous example.

Upvotes: 1

Views: 55

Answers (2)

gen_Eric
gen_Eric

Reputation: 227310

Take a peek at the source for $.each, and you will see what's going on here.

for (; i < length; i++) {
    value = callback.call(obj[i], i, obj[i]);

    if (value === false) {
        break;
    }
}

From: http://james.padolsey.com/jquery/#v=1.10.2&fn=jQuery.each

jQuery is using .call() to trigger your callback function. According to Mozilla's docs for .call:

Note that this may not be the actual value seen by the method: if the method is a function in non-strict mode code, null and undefined will be replaced with the global object, and primitive values will be boxed.

From: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call

Upvotes: 2

Mark Pieszak - Trilon.io
Mark Pieszak - Trilon.io

Reputation: 67141

From the docs: jQuery.each() documentation

The $.each() function is not the same as $(selector).each(), which is used to iterate, exclusively, over a jQuery object. The $.each() function can be used to iterate over any collection, whether it is an object or an array. In the case of an array, the callback is passed an array index and a corresponding array value each time.

More importantly:

(The value can also be accessed through the this keyword, but Javascript will always wrap the this value as an Object even if it is a simple string or number value.) The method returns its first argument, the object that was iterated.

It looks to me like, since it is trying to wrap null as an object, jQuery must return window for you.

I would always suggest using the value (2nd parameter) of the callback function instead of this within these kinds of loops though.

$.each(z, function(key, value){
    console.log(value);
}); 

Upvotes: 1

Related Questions