Will `for (var a of null) {}` throw an error?
To me since IsCallable(undefined)
is false
, so it throws an TypeError
. Traceur and V8 will both throw a TypeError
saying that cannot read property @@iterator from undefined or null, and Firefox throws a TypeError
saying that null have no property. So it should be an error.
In that case we have a gotcha.
Is there any interest to change that behavior? Since es6 isn’t finial yet.
for in and for of do completely different things and there is no reason to expect consistency between them.
This was discussed already; search esdiscuss.org.
Thanks. Found that discussion, and after thinking about it again, throwing errors on null/undefined actually makes sense, because it’s impossible to sliently loop over null/undefined with regular for loop (if you check length directly) or forEach directly. So throwing an error is actually consistent with how things work in es3/5.
Actually I propose a change in texts in the specification.
CheckIterable ( obj )>1. If obj is
undefined
ornull
, then returnundefined
.>2. If type(obj) is Object, then return Get(obj, @@iterator).>3. Let box be ToObject(obj).>4. ReturnIfAbrupt(box).>5. Return the result of calling the [[Get]] internal method of box passing @@iterator and obj as the arguments.
This is way more too complex. We know that there are three situation:1. obj is undefined
or null
2. obj is of a primitive type3. obj is an object
In 1, we don't care if it returns undefined or throw a TypeError. In ES6 spec, there are two uses of the undefined returned. One of them passes it as F to Call, the other passes it to ToObject. Both of them will result in TypeError. So we can just let this step throw TypeError instead of return undefined
.
I suggest we can a little bit combine these steps:
CheckIterable (obj)>1. Let box be ToObject(obj).>2. ReturnIfAbrupt(box).>3. Return the result of calling the [[Get]] internal method of box passing @@iterator and obj as the arguments.
If obj is undefined
or null
, the first step will fail and throw TypeError. If obj is primitive, it's boxed. If obj is an object, it is no-op in ToObject.
Your suggestion breaks Array.from and TypedArrayFrom.
Date: Mon, 22 Dec 2014 21:28:54 -0800 From: brendan at mozilla.org
Your suggestion breaks Array.from and TypedArrayFrom.
In the spec:
- Let arrayLike be ToObject(items).
A type error will also be thrown since null and undefined are not ObjectCoercible.
Oops, you're right in these cases. The CheckIterable spec helper seems over-general. Allen?
actually, in my working copy of the spec, CheckIterable has already been updated to look like:
1. If obj is undefined or null, then return undefined.
2. Return GetV(obj, @@iterator).
where GetV is similar to Get but it boxes non-object values before doing the property lookup
When you find issues like this, the best thing to do is to simply submit a bug ticket at: bugs.emcascript.org
Ideally it shouldn’t, because its twin
for (var a in null) {}
won’t.But looking at step 8 in people.mozilla.org/~jorendorff/es6-draft.html#sec-runtime-semantics-forin-div-ofexpressionevaluation-abstract-operation, people.mozilla.org/~jorendorff/es6-draft.html#sec-runtime-semantics-forin-div-ofexpressionevaluation-abstract-operation, when passing
null
toGetIterator()
, it will throw a type error when the result of step 2CheckIterable(null)
, which isundefind
, is called in step 3 in the algorithm forGetIterator()
.Did I miss something or the current spec does throw an error?