Make collection iterators actually iterable

The ES6 spec calls for this so these iterators are usable in for-of loops, with spread operators, etc.
This commit is contained in:
Scott Kyle 2016-03-19 19:55:19 -07:00
parent b5ce02c0ce
commit 8c66bab8aa
2 changed files with 50 additions and 32 deletions

View File

@ -20,6 +20,19 @@
var arrayPrototype = Array.prototype; var arrayPrototype = Array.prototype;
// eslint-disable-next-line no-undef
var iteratorSymbol = typeof Symbol != 'undefined' && Symbol.iterator;
var iteratorPrototype = {};
if (iteratorSymbol) {
// These iterators should themselves be iterable.
Object.defineProperty(iteratorPrototype, iteratorSymbol, {
value: function() {
return this;
}
});
}
[ [
'join', 'join',
'slice', 'slice',
@ -43,35 +56,36 @@ var arrayPrototype = Array.prototype;
var self = this; var self = this;
var index = 0; var index = 0;
return { return Object.create(iteratorPrototype, {
next: function() { next: {
if (!self || index >= self.length) { value: function() {
self = null; if (!self || index >= self.length) {
return {done: true, value: undefined}; self = null;
} return {done: true, value: undefined};
}
var value; var value;
switch (methodName) { switch (methodName) {
case 'entries': case 'entries':
value = [index, self[index]]; value = [index, self[index]];
break; break;
case 'keys': case 'keys':
value = index; value = index;
break; break;
default: default:
value = self[index]; value = self[index];
} }
index++; index++;
return {done: false, value: value}; return {done: false, value: value};
}
} }
}; });
}; };
exports[methodName] = {value: method}; exports[methodName] = {value: method};
}); });
/* global Symbol */ if (iteratorSymbol) {
if (typeof Symbol != 'undefined' && Symbol.iterator) { exports[iteratorSymbol] = exports.values;
exports[Symbol.iterator] = exports.values;
} }

View File

@ -576,20 +576,24 @@ module.exports = BaseTest.extend({
TestCase.assertEqual(list.reduce(function(n, p) {return n + p.age}, 0), 33); TestCase.assertEqual(list.reduce(function(n, p) {return n + p.age}, 0), 33);
TestCase.assertEqual(list.reduceRight(function(n, p) {return n + p.age}, 0), 33); TestCase.assertEqual(list.reduceRight(function(n, p) {return n + p.age}, 0), 33);
[ // eslint-disable-next-line no-undef
'entries', var iteratorSymbol = typeof Symbol != 'undefined' && Symbol.iterator;
'keys', var iteratorMethodNames = ['entries', 'keys', 'values'];
'values',
typeof Symbol != 'undefined' && Symbol.iterator, // eslint-disable-line no-undef
].forEach(function(methodName) {
if (!methodName) {
return;
}
if (iteratorSymbol) {
iteratorMethodNames.push(iteratorSymbol);
}
iteratorMethodNames.forEach(function(methodName) {
var iterator = list[methodName](); var iterator = list[methodName]();
var count = 0; var count = 0;
var result; var result;
if (iteratorSymbol) {
// This iterator should itself be iterable.
TestCase.assertEqual(iterator[iteratorSymbol](), iterator);
}
while ((result = iterator.next()) && !result.done) { while ((result = iterator.next()) && !result.done) {
var value = result.value; var value = result.value;