2

This is so simple I am baffled. I have the following:

var x = 'shrimp';    
var stypes = new Array('shrimp', 'crabs', 'oysters', 'fin_fish', 'crawfish', 'alligator');
for (t in stypes) {
    if (stypes[t] != x) {
        alert(stypes[t]);
    }
}

Once the values have iterated it starts returning a dozen functions like

function (iterator, context) {
    var index = 0;
    iterator = iterator.bind(context);
    try {
        this._each(function (value) {iterator(value, index++);});
    } catch (e) {
        if (e != $break) {
            throw e;
        }
    }
    return this;
}

What the heck is going on?

Edit: In these scripts I am using http://script.aculo.us/prototype.js and http://script.aculo.us/scriptaculous.js I remember now reading about the way prototype extends arrays and I am betting this is part of it. How do I deal with it?

1
  • I was just about to say... that code works fine for me, something must have prototyped Array differently. I'd go with Quintin's answer. Commented Sep 29, 2009 at 23:26

4 Answers 4

7

The for enumeration is going to go over every member of the object you passed it. In this case an array, which happens to have functions as members as well as the elements passed.

You could re-write your for loop to check if typeof stypes[t] == "function" or yada yada. But IMO you are better off just modifying your looping to only elements..

for(var i = 0, t; t = stypes[i]; ++i){
    if (t != x) {
        alert(t);
    }
}

Or

for(var i = 0; i < stypes.length; ++i){
    if (stypes[i] != x) {
        alert(stypes[i]);
    }
}

I wanted to migrate my last comment up to the answer to add the notice of the a caveat for the first type of loop.

from Simon Willison's "A re-introduction to JavaScript"..

for (var i = 0, item; item = a[i]; i++) {
    // Do something with item
}

Here we are setting up two variables. The assignment in the middle part of the for loop is also tested for truthfulness - if it succeeds, the loop continues. Since i is incremented each time, items from the array will be assigned to item in sequential order. The loop stops when a "falsy" item is found (such as undefined).

Note that this trick should only be used for arrays which you know do not contain "falsy" values (arrays of objects or DOM nodes for example). If you are iterating over numeric data that might include a 0 or string data that might include the empty string you should use the i, j idiom instead.

Sign up to request clarification or add additional context in comments.

5 Comments

Any explanation for the downvote, I'm very interested in the reason for it.
Just to add to your correct answer: "for..in" crawls up the Array.prototype chain. See ecma-international.org/publications/standards/Ecma-262.htm (Sec 12.6.4), while a standard for loop does not. Also, the order of items iterated with "for..in" is not guaranteed. A standard for loop is.
This worked for me. I've upvoted you back to zero. I am not familiar with this syntax in for() for(var i = 0, t; What is that called?
I can't recall the proper name for it (if there is one), but you should note a caveat that if any of the elements of the array are null or possibly falsy then the loop will quit at that element. Just something to be aware of when using this syntax vs a standard index iteration.
Thank you for the further explanation Quintin! I'm learning!
3

you want to do:

for (var i in object) {
    if (!object.hasOwnProperty(i))
        continue;
    ... do stuff ...
}

As for..in enumeration iterates over all properties (enumerable or otherwise) that exist on both the object and its prototype chain. The hasOwnProperty check restricts iteration to just those properties on the actual object you want to enumerate.

ES5 makes things a little better for library developers (and help avoid this stuff) but we won't see that ina shipping browser for quite a while :-(

[edit: replacing return with continue. lalalalala ;) ]

1 Comment

You want to continue;, not return;.
1

Since prototype has extended the array for your convenience you should take advantage of it. Your example could be rewritten as:

var x = 'shrimp';    
var stypes = new Array('shrimp', 'crabs', 'oysters', 'fin_fish', 'crawfish', 'alligator');
stypes.without(x).each(alert);

Comments

-3

It should be

for (t in stypes) {
    if (t != x) {
        alert(t);
    }
}

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.