Hey Joe,

> ARE there any good uses for this
> loop method?

Absolutely, I use it all the time! Remember that as the linked article
says:

> ...`for..in` is not for iterating through the /indexes/ of an
> /array/.  `for..in` iterates through the /property names/ of an
> /object/.  Arrays are objects, and their element indexes are
> property names (array elements are really just object
> properties), but arrays can have /other/ properties as well,
> which will break your `for..in` loops if you assume they only
> loop through array indexes...

Having a tool that loops through the names of all of the properties of
the object is very useful indeed! JavaScript objects are associative
arrays (aka dictionaries, aka maps), which makes them very handy
indeed. Let's keep track of scores in a game:

    var scores, name;

    scores = {}; // blank object
    scores['Mohammed'] = 23;
    scores['Alice'] = 47;
    scores['Ping'] = 14;

    for (name in scores) {
        display(name + ": " + scores[name]);
    }

That displays:

    Mohammed: 23
    Alice: 47
    Ping: 14

(The order is not defined, at least not as of the 3rd edition spec --
I'll have to check the new 5th edition spec, but for general-purpose
use 3rd edition is still all you can [mostly] rely on for now.)

Prototype uses for..in for lots of things, including its inheritance
mechanism. It's very handy for what it actually does, but the myth
that it loops through the indexes of an array is just that, a myth.

The new ECMAScript 5th ed. spec defines a bunch of new methods on
Array that are similar to Prototype's Enumerable methods, so those are
handy if you don't mind using functions on each iteration, which is
harmless most of the time. And of course, since you're using
Prototype, you already have access to them (albeit -- for now -- with
slightly different names).

HTH,

-- T.J. :-)

On Feb 23, 3:37 am, "joe t." <[email protected]> wrote:
> TJ,
> i see endless warnings against using for/in. And i understand the
> reasons for them, especially on arrays. But it seems like a fairly
> powerful looping tool, yet no one seems to temper the warnings with
> appropriate circumstances for its use. Since the JS spec disallows
> creating non-enumerable properties, ARE there any good uses for this
> loop method?
>
> Thanks,
> -joe t.
>
> On Feb 22, 9:08 am, "T.J. Crowder" <[email protected]> wrote:
>
>
>
> > Hi,
>
> > That for..in code is incorrect, based on a misconception (a common
> > one). This page explains the misconception and discusses correct ways
> > of iterating through 
> > arrays:http://proto-scripty.wikidot.com/prototype:tip-looping-through-arrays
>
> > HTH,
> > --
> > T.J. Crowder
> > Independent Software Consultant
> > tj / crowder software / comwww.crowdersoftware.com
>
> > On Feb 22, 12:13 pm, Dale <[email protected]> wrote:
>
> > > Hi
>
> > > I tried a simple javascript example on the w3school 
> > > (http://www.w3schools.com/JS/js_loop_for_in.asp),  and the example works 
> > > fine
> > > if I don't include scriptaculous or prototype, but once I do I keep
> > > getting a strange error.
>
> > > Anyone know why this error/bug shows up, or have I done something very
> > > strange in my code ?
>
> > > Thanks for any help... examples below...
>
> > > The normal example:
> > > <html>
> > > <body>
>
> > > <script type="text/javascript">
> > > var x;
> > > var mycars = new Array();
> > > mycars[0] = "Saab";
> > > mycars[1] = "Volvo";
> > > mycars[2] = "BMW";
>
> > > for (x in mycars)
> > >   {
> > >   document.write(mycars[x] + "<br />");
> > >   }
> > > </script>
>
> > > </body>
> > > </html>
> > > Output of this one is:
> > > Saab
> > > Volvo
> > > BMW
>
> > > The modified example including the library:
> > > <html>
> > > <head>
> > > <script src="javascript/prototype.js" type="text/javascript"></script>
> > > <script src="javascript/scriptaculous.js" type="text/javascript"></
> > > script>
> > > </head>
> > > <body>
> > > <script type="text/javascript">
> > > var x;
> > > var mycars = Array();
> > > mycars[0] = "Saab";
> > > mycars[1] = "Volvo";
> > > mycars[2] = "BMW";
>
> > > for (x in mycars)
> > > {
> > > document.write(mycars[x] + "<br />");}
>
> > > </script>
> > > </body>
> > > </html>
>
> > > Output of this one is:
> > > Saab
> > > Volvo
> > > BMW
> > > function each(iterator, context) { var index = 0; try
> > > { this._each(function (value) {iterator.call(context, value, index+
> > > +);}); } catch (e) { if (e != $break) { throw e; } } return this; }
> > > function eachSlice(number, iterator, context) { var index = - number,
> > > slices = [], array = this.toArray(); if (number < 1) { return array; }
> > > while ((index += number) < array.length)
> > > { slices.push(array.slice(index, index + number)); } return
> > > slices.collect(iterator, context); }
> > > function all(iterator, context) { iterator = iterator || Prototype.K;
> > > var result = true; this.each(function (value, index) {result = result
> > > && !!iterator.call(context, value, index);if (!result) {throw
> > > $break;}}); return result; }
> > > function any(iterator, context) { iterator = iterator || Prototype.K;
> > > var result = false; this.each(function (value, index) {if ((result = !!
> > > iterator.call(context, value, index))) {throw $break;}}); return
> > > result; }
> > > function collect(iterator, context) { iterator = iterator ||
> > > Prototype.K; var results = []; this.each(function (value, index)
> > > {results.push(iterator.call(context, value, index));}); return
> > > results; }
> > > function detect(iterator, context) { var result; this.each(function
> > > (value, index) {if (iterator.call(context, value, index)) {result =
> > > value;throw $break;}}); return result; }
> > > function findAll(iterator, context) { var results = [];
> > > this.each(function (value, index) {if (iterator.call(context, value,
> > > index)) {results.push(value);}}); return results; }
> > > function findAll(iterator, context) { var results = [];
> > > this.each(function (value, index) {if (iterator.call(context, value,
> > > index)) {results.push(value);}}); return results; }
> > > function grep(filter, iterator, context) { iterator = iterator ||
> > > Prototype.K; var results = []; if (Object.isString(filter)) { filter =
> > > new RegExp(RegExp.escape(filter)); } this.each(function (value, index)
> > > {if (filter.match(value)) {results.push(iterator.call(context, value,
> > > index));}}); return results; }
> > > function include(object) { if (Object.isFunction(this.indexOf)) { if
> > > (this.indexOf(object) != -1) { return true; } } var found = false;
> > > this.each(function (value) {if (value == object) {found = true;throw
> > > $break;}}); return found; }
> > > function include(object) { if (Object.isFunction(this.indexOf)) { if
> > > (this.indexOf(object) != -1) { return true; } } var found = false;
> > > this.each(function (value) {if (value == object) {found = true;throw
> > > $break;}}); return found; }
> > > function inGroupsOf(number, fillWith) { fillWith =
> > > Object.isUndefined(fillWith) ? null : fillWith; return
> > > this.eachSlice(number, function (slice) {while (slice.length < number)
> > > {slice.push(fillWith);}return slice;}); }
> > > function inject(memo, iterator, context) { this.each(function (value,
> > > index) {memo = iterator.call(context, memo, value, index);}); return
> > > memo; }
> > > function invoke(method) { var args = $A(arguments).slice(1); return
> > > this.map(function (value) {return value[method].apply(value,
> > > args);}); }
> > > function max(iterator, context) { iterator = iterator || Prototype.K;
> > > var result; this.each(function (value, index) {value =
> > > iterator.call(context, value, index);if (result == null || value >=
> > > result) {result = value;}}); return result; }
> > > function min(iterator, context) { iterator = iterator || Prototype.K;
> > > var result; this.each(function (value, index) {value =
> > > iterator.call(context, value, index);if (result == null || value <
> > > result) {result = value;}}); return result; }
> > > function partition(iterator, context) { iterator = iterator ||
> > > Prototype.K; var trues = [], falses = []; this.each(function (value,
> > > index) {(iterator.call(context, value, index) ? trues :
> > > falses).push(value);}); return [trues, falses]; }
> > > function pluck(property) { var results = []; this.each(function
> > > (value) {results.push(value[property]);}); return results; }
> > > function reject(iterator, context) { var results = [];
> > > this.each(function (value, index) {if (!iterator.call(context, value,
> > > index)) {results.push(value);}}); return results; }
> > > function sortBy(iterator, context) { return this.map(function (value,
> > > index) {return {value: value, criteria: iterator.call(context, value,
> > > index)};}).sort(function (left, right) {var a = left.criteria, b =
> > > right.criteria;return a < b ? -1 : a > b ? 1 : 0;}).pluck("value"); }
> > > function clone() { return slice.call(this, 0); }
> > > function toArray() { return this.map(); }
> > > function zip() { var iterator = Prototype.K, args = $A(arguments); if
> > > (Object.isFunction(args.last())) { iterator = args.pop(); } var
> > > collections = [this].concat(args).map($A); return this.map(function
> > > (value, index) {return iterator(collections.pluck(index));}); }
> > > function size() { return this.length; }
> > > function inspect() { return "[" + this.map(Object.inspect).join(", ")
> > > + "]"; }
> > > function detect(iterator, context) { var result; this.each(function
> > > (value, index) {if (iterator.call(context, value, index)) {result =
> > > value;throw $break;}}); return result; }
> > > function reverse() { [native code] }
> > > function forEach() { [native code] }
> > > function clear() { this.length = 0; return this; }
> > > function first() { return this[0]; }
> > > function last() { return this[this.length - 1]; }
> > > function compact() { return this.select(function (value) {return
> > > value != null;}); }
> > > function flatten() { return this.inject([], function (array, value)
> > > {if (Object.isArray(value)) {return array.concat(value.flatten());}
> > > array.push(value);return array;}); }
> > > function without() { var values = slice.call(arguments, 0); return
> > > this.select(function (value) {return !values.include(value);}); }
> > > function uniq(sorted) { return this.inject([], function (array, value,
> > > index) {if (0 == index || (sorted ? array.last() != value : !
> > > array.include(value))) {array.push(value);}return array;}); }
> > > function intersect(array) { return this.uniq().findAll(function (item)
> > > {return array.detect(function (value) {return item === value;});}); }
> > > function clone() { return slice.call(this, 0); }
> > > function toJSON() { var results = []; this.each(function (object) {var
> > > value = Object.toJSON(object);if (!Object.isUndefined(value))
> > > {results.push(value);}}); return "[" + results.join(", ") + "]"; }

-- 
You received this message because you are subscribed to the Google Groups 
"Prototype & script.aculo.us" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/prototype-scriptaculous?hl=en.

Reply via email to