3

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?

2
  • What does square bracket in ['.b'] means? Commented Jan 12, 2013 at 16:17
  • @JustinJohn it is n array with one element. $.each can be used to loop over arrays or objects Commented Jan 12, 2013 at 16:28

3 Answers 3

5

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"
});
Sign up to request clarification or add additional context in comments.

1 Comment

+1 - Although the (currently accepted) answer by @charlietftl basically says the same thing, this answer has a great explanation of why the this inside array based eaches is a bad idea.
2

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/

Comments

0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.