jsdc icon indicating copy to clipboard operation
jsdc copied to clipboard

for of简化为for in,无需迭代器

Open army8735 opened this issue 9 years ago • 12 comments

army8735 avatar Apr 13 '15 08:04 army8735

@hax 有可能有陷阱吗

army8735 avatar Apr 13 '15 13:04 army8735

我没懂意思。你是要改哪里的代码?

先可大概说下差异。 for-of走迭代器,因为每次要产生object形如{value:x, done:false},对于当前浏览器来说略有性能开销。 for-in是遍历key,要上溯prototype,且要把所有key按照特定规则排序(先数字排序后其他按原始顺序),其实也慢得很,说不定比for-of还慢。 要快,目前还是用for/while循环。另外数组上的forEach之类的方法似乎现在浏览器优化得不错,跟直接循环的性能相当。

hax avatar Apr 14 '15 03:04 hax

目前for of是翻译成了迭代器循环来实现:

for(a of b) {
}
for(a =b.next();!a.done;a=b.next()) {a=a.value;
}

但其实翻译成for in循环更简单:

for(a in b) {a=b[a]
}

可省略迭代器的shim实现。

但怕有哪里不支持什么的。

army8735 avatar Apr 14 '15 04:04 army8735

这个翻译有问题。必须是

_it = b[Symbol.iterator]()
while(!(_x = _it.next()).done) { a = _x.value }

翻译成 for-in 应该是不对的。

hax avatar Apr 14 '15 06:04 hax

Symbol.iterator?

army8735 avatar Apr 14 '15 07:04 army8735

见这里:https://people.mozilla.org/~jorendorff/es6-draft.html#sec-well-known-symbols

Specification Name [[Description]] Value and Purpose
@@iterator "Symbol.iterator" A method that returns the default Iterator for an object. Called by the semantics of the for-of statement.

hax avatar Apr 14 '15 07:04 hax

thx

army8735 avatar Apr 14 '15 07:04 army8735

当然,如果是老浏览器就需要runtime的Symbol shim/sham。 就算没有Symbol,兼容起来也不是很难,见:https://github.com/hax/my-promise/blob/master/src/Promise.js#L421-L436 可以看到在没有提供iterator时直接退化为数组遍历,当然做得更好一点,可以提供其他iteratable类型的默认实现。

hax avatar Apr 14 '15 07:04 hax

for in的话,不能遍历迭代器吗?

army8735 avatar Apr 14 '15 08:04 army8735

应该不行。见这里:https://people.mozilla.org/~jorendorff/es6-draft.html#sec-runtime-semantics-forin-div-ofheadevaluation-tdznames-expr-iterationkind-labelset

按照我读spec的理解: iterationKind对于for-in来说总是enumerate,对于for-of来说总是iterate。前者总是直接调用确定的[[Enumerate]](),除了Proxy可以改这个行为,其他所有对象的enumerate行为都是spec指定的(也就是和以前一样的行为)。也就是说for-in不会调用自定义迭代器。

hax avatar Apr 16 '15 05:04 hax

只是spec规定的默认迭代器的行为大多就是基于[[Enumerate]]。所以如果用户没有customize过,则for-of的行为和for-in是一致的。因此理论上应该可以做优化。我前面贴的例子里的这几行https://github.com/hax/my-promise/blob/master/src/Promise.js#L425-L429 就是:iterable如果没有自定义iterator,我就认为它是数组,然后就按数组遍历来优化。

所以有一种优化可能就是,如果是一个局部变量我们明确知道它的类型(比如是数组),并且Array.prototype[Symbol.iterator]没有被改写。则我们可以直接编译为for(;;)循环。

hax avatar Apr 16 '15 05:04 hax

补充:babel有可选的loose mode,其行为略有不同(tracer似乎也有)。 另外iterator的行为严格来说还有捕捉异常和触发iterator的return方法。参见这两个issue: https://github.com/google/traceur-compiler/issues/1773 https://github.com/babel/babel/issues/838

hax avatar May 04 '15 06:05 hax