如果您正在使用ES2015,并且想要定义一个像2-D数组一样迭代的自己的对象,可以通过实现
迭代器协议来完成:
- 定义一个名为
Symbol.iterator
的@@iterator函数,它返回...
- ...一个具有
next()
函数的对象,该函数返回...
- ...一个具有一个或两个属性的对象:一个可选的包含下一个值(如果有)的
value
和一个布尔值done
,如果我们完成了迭代,则为true。
一个
一维数组迭代器函数看起来像这样:
function Cubes() {
this.cubes = [1, 2, 3, 4];
this.numVals = this.cubes.length;
this[Symbol.iterator] = function () {
var index = -1;
var self = this;
return {
next: function() {
index++;
if (index < self.numVals) {
return {
value: self.cubes[index],
done: false
};
}
return {done: true}
}
};
};
}
现在,我们可以将我们的
Cubes
对象视为可迭代对象:
var cube = new Cubes();
console.log([...cube]);
for (var value of cube) {
console.log(value);
}
创建我们自己的 2-D 可迭代对象,可以在我们的 next() 函数中返回另一个可迭代对象,而不是返回值:
function Cubes() {
this.cubes = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
];
this.numRows = this.cubes.length;
this.numCols = this.cubes[0].length;
this[Symbol.iterator] = function () {
var row = -1;
var self = this;
function createColIterator(currentRow) {
var col = -1;
var colIterator = {}
colIterator[Symbol.iterator] = function() {
return {next: function() {
col++;
if (col < self.numCols) {
return {
value: self.cubes[currentRow][col],
done: false
};
}
return {done: true};
}};
}
return colIterator;
}
return {next: function() {
row++;
if (row < self.numRows) {
return {
value: createColIterator(row),
done: false
};
}
return {done: true}
}};
};
}
现在,我们可以使用嵌套迭代:
var cube = new Cubes();
var rows = [...cube];
console.log([...rows[0]]);
console.log([...rows[1]]);
console.log([...rows[2]]);
console.log([...cube].map(function(iterator) {
return [...iterator];
}));
for (var row of cube) {
for (var value of row) {
console.log(value);
}
}
请注意,我们的自定义可迭代对象并不在所有情况下都像二维数组一样;例如,我们没有实现
map()
函数。
这个答案展示了如何实现一个生成器映射函数(
请看此处了解迭代器和生成器之间的差异;此外,生成器是ES2016功能,而不是ES2015,因此如果您使用babel编译,需要
更改您的babel预设)。
forEach()
更短地重写。请参考我的回答中的示例。 - 0stone0