0

I'm writing a random generator that runs through an array, and randomizes the items in the array, then outputs it to HTML.

The below code works, however I repurposed it from various places and I'd like to understand how this for loop works, specifically, I don't know what for (var c in cars) checks for, and I've tried simply replacing each instance of cars in the loop, but it doesn't output anything then.

Here is a functioning codepen: http://codepen.io/npav/pen/xZXxqe

Just the JS:

var cars = 'Tarasenko,Steen,Backes,Stastny,Jaskin,Ott,Brodziak,Upshall,Rattie,Fabbri,Brouwer, Berglund'.split(',');

cars.sort(function() { return 0.5 - Math.random() });

for (var c in cars) {
    var newElement = document.createElement('div');
    newElement.id = cars[c]; newElement.className = "car";
    newElement.innerHTML = cars[c];
    document.getElementById("forwards").appendChild(newElement);
}
npav42
  • 53
  • 9
  • Possible duplicate: http://stackoverflow.com/questions/500504/why-is-using-for-in-with-array-iteration-such-a-bad-idea – joaumg Jan 15 '16 at 02:02
  • 1
    It cycles over `cars`, referring to the current value index (0,1,2,...) as `c`. See also [`for...of`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of). – Sampson Jan 15 '16 at 02:03
  • 1
    For..in iterates over the enumerable values of the object. In this case, that is the index of the array. It can also be the properties of a more generic object. Here's the docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in – Jason Kennaly Jan 15 '16 at 02:05
  • @sampson Thanks, so if I changed `var cars` to `var players`, along with all the other instances of `cars`, it would then cycle through `players'? – npav42 Jan 15 '16 at 02:06
  • I was wondering how this code even works. But hey, there's actually a `.split(',');` at the end of cars. That explains everything. – choz Jan 15 '16 at 02:06
  • 1
    @npav42 Yes, based on this code. If you change `cars` to `players`, you've not changed the structure of the code. Only a variable name. – Sampson Jan 15 '16 at 02:07
  • 1
    @sampson just tried and everything works, thanks for your help. – npav42 Jan 15 '16 at 02:11

2 Answers2

0

So, unlike a standard for loop that uses a counter, this goes through all the enumerable keys of the object. There are different ways to do this. The spec, ECMA 262/51/#sec-12.6.4, "The for-in Statement" has this to say (some links and highlighting lost in quotation):

The production IterationStatement : for ( var VariableDeclarationNoIn in Expression ) Statement is evaluated as follows:

  1. Let varName be the result of evaluating VariableDeclarationNoIn.
  2. Let exprRef be the result of evaluating the Expression.
  3. Let experValue be GetValue(exprRef).
  4. If experValue is null or undefined, return (normal, empty, empty).
  5. Let obj be ToObject(experValue).
  6. Let V = empty.
  7. Repeat

    a. Let P be the name of the next property of obj whose [[Enumerable]] attribute is true. If there is no such property, return (normal, V, empty).

    b. Let varRef be the result of evaluating varName as if it were an Identifier Reference (11.1.2); it may be evaluated repeatedly. c. Call PutValue(varRef, P).

    d. Let stmt be the result of evaluating Statement.

    e. If stmt.value is not empty, let V = stmt.value.

    f. If stmt.type is break and stmt.target is in the current label set, return (normal, V, empty).

    g. If stmt.type is not continue || stmt.target is not in the current label set, then

    i. If stmt is an abrupt completion, return stmt.

The mechanics and order of enumerating the properties (..., step 7.a in the second) is not specified.

Note that I didn't post the entire section, and that the algorithm is different based on if you do for(x in y) or for(var x in y)

Matthew Herbst
  • 29,477
  • 23
  • 85
  • 128
0

Since I can't comment yet.. Your use of for-in loop is wrong. for-in loops through the properties of an object and doesn't necessarily mean that the object should be an array. Please see this

var obj = {a:1, b:2, c:3};

for (var prop in obj) {
  console.log("obj." + prop + " = " + obj[prop]);
}

// Output:
// "obj.a = 1"
// "obj.b = 2"
// "obj.c = 3"

Based on your code, I would suggest using a for-loop.

for (var i = 0; i < cars.length; i++) {
    var newElement = document.createElement('div');
    newElement.id = cars[i]; newElement.className = "car";
    newElement.innerHTML = cars[i];
    document.getElementById("forwards").appendChild(newElement);
}