function evaluate(for ( LeftHandSideExpression in Expression ) Statement) {
var exprRef = evaluate(Expression);
var experValue = GetValue(exprRef);
if (experValue === null || experValue === undefined) return Completion('normal', undefined, undefined);
var obj = ToObject(experValue);
var V = undefined;
for (P in obj) { // use undefined order, skip deleted properties and optionally process added properties (during the loop)
if (!P.[[Enumerable]]) continue; // skip non-enumerable properties
var lhsRef = evaluate(LeftHandSideExpression); // may be evaluated repeatedly
PutValue(lhsRef, P);
var stmt = evaluate(Statement);
if (stmt.value !== undefined) V = stmt.value;
if (stmt.type == 'break' && labels.indexOf(stmt.target) >= 0) return Completion('normal', V, undefined);
if (stmt.type != 'continue' || labels.indexOf(stmt.target) < 0) {
if (stmt.isAbrubt()) return stmt;
}
}
return Completion('normal', V, undefined);
}
The alternative production for this loop is almost identical, except for the first step and how the Identifier is gotten. In fact, specification wise, using a var is actually slower, because it needs to bounce the binding after the first time...
function evaluate(for ( LeftHandSideExpression in Expression ) Statement) {
var varName = evaluate(VariableDeclarationNoIn);
var exprRef = evaluate(Expression);
var experValue = GetValue(exprRef);
if (experValue === null || experValue === undefined) return Completion('normal', undefined, undefined);
var obj = ToObject(experValue);
var V = undefined;
for (P in obj) { // use undefined order, skip deleted properties and optionally process added properties (during the loop)
if (!P.[[Enumerable]]) continue; // skip non-enumerable properties
var varRef = evaluate(varName); // as 11.1.2, Identifier Reference. may be evaluated repeatedly
PutValue(varRef, P);
var stmt = evaluate(Statement);
if (stmt.value !== undefined) V = stmt.value;
if (stmt.type == 'break' && labels.indexOf(stmt.target) >= 0) return Completion('normal', V, undefined);
if (stmt.type != 'continue' || labels.indexOf(stmt.target) < 0) {
if (stmt.isAbrubt()) return stmt;
}
}
return Completion('normal', V, undefined);
}
Note that the order of enumeration is not defined so depends on the implementation. Unvisited items that are deleted from the object you are iterating over, during an iteration, should not show up during remainder of the iteration. Properties added during an iteration may be iterated over, but this also depends on the implemenation.
Enumerating the properties of an object also enumerates the properties of its prototype (all the way up the chain), recursively.
Shadowed variables are not enumerated (for instance if this object has a property that also exists in its prototype).
See also 11.13.1 (simple assignment).