Randomblue
Randomblue

Reputation: 116443

jQuery: Using string passed by $.each

This is my code:

<div class='a'>
  <div class='b'>Test</div>
</div>

and

$(['.b']).each(function () {
  console.log($('.a').find(this).text()); // Expecting to print "Test"
});

I expect the console.log to print Test, but it doesn't! Is this a jQuery bug?

Upvotes: 3

Views: 840

Answers (3)

Andrew Whitaker
Andrew Whitaker

Reputation: 126082

There are a few problems here.

  1. When you call jQuery with an array (like you're doing), jQuery expects it to be an array of DOM elements.
  2. If you want to use $.each, use the static version that iterates over generic objects or arrays.

With both of those things said, there's stil an issue with using $.each with an array containing primitive values. The following code exhibits the same problem you were seeing:

$.each([".b"], function () {
    console.log($('.a').find(this).text()); // Expecting to print "Test"
});

Inside the callback function for .each, this is a String object and not a string primitive. To understand this, we need to look at what .each is doing under the hood:

for (; i < length;) {
    if (callback.apply(object[i++], args) === false) { // <----
        break;
    }
}

The important bit is the call to apply. According to the ECMAScript specification, when a primitive value is passed to apply, the value's toObject method is called:

If thisArg is null or undefined, the called function is passed the global object as the this value. Otherwise, the called function is passed ToObject(thisArg) as the this value.

This explains why your code was not working-- .find expects a string primitive and not a String object.

This is why the documentation for $.each actually mentions using this with primitive values:

(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.).

Therefore the way to fix the problem with your code is to leverage the element argument that's passed to the callback function:

$.each([".b"], function (_, item) {
    console.log($('.a').find(item).text()); // Expecting to print "Test"
});

Upvotes: 5

Mattias Buelens
Mattias Buelens

Reputation: 20179

That's because you're on the dark side of JavaScript.

In JavaScript, this is always made into an Object so that typeof this === "object", no matter what this was actually bound to. Even when a primitive string is bound to the this context (which you'd expect to give typeof this === "string"), this is actually a String object and typeof this === "object". Here's a more thorough explanation of this behaviour.

When iterating over arrays of non-objects, you should use the second argument of your callback function as value.

$(['.b']).each(function (index, value) {
  console.log($('.a').find(value).text()); // Expecting to print "Test"
});

Upvotes: 0

charlietfl
charlietfl

Reputation: 171698

Don't use this inside each when looping over an array. It works fine on objects or collection of elemnts but fails with arrays.

Use second argument of each to access array element

$(['.b']).each(function (index, item) {
  console.log($('.a').find(item).text()); // Expecting to print "Test"
});

DEMO http://jsfiddle.net/KbuZK/

Upvotes: 2

Related Questions