如果您使用ES2015并且要定义自己的对象,像2-d数组迭代,你可以实现iterator protocol通过:
- 定义一个@@迭代函数调用
Symbol.iterator
返回...
- ...与
next()
函数返回对象...
- ...与一个或两个属性的对象:可选
value
与下一个值(如果有一个)和一个布尔done
这是真的,如果我们完成迭代。
一个一维阵列迭代函数应该是这样的:
// our custom Cubes object which implements the iterable protocol
function Cubes() {
this.cubes = [1, 2, 3, 4];
this.numVals = this.cubes.length;
// assign a function to the property Symbol.iterator
// which is a special property that the spread operator
// and for..of construct both search for
this[Symbol.iterator] = function() { // can't take args
var index = -1; // keep an internal count of our index
var self = this; // access vars/methods in object scope
// the @@iterator method must return an object
// with a "next()" property, which will be called
// implicitly to get the next value
return {
// next() must return an object with a "done"
// (and optionally also a "value") property
next: function() {
index++;
// if there's still some values, return next one
if (index < self.numVals) {
return {
value: self.cubes[index],
done: false
};
}
// else there's no more values left, so we're done
// IF YOU FORGET THIS YOU WILL LOOP FOREVER!
return {done: true}
}
};
};
}
现在,我们可以把我们的Cubes
对象像一个迭代:
var cube = new Cubes(); // construct our cube object
// both call Symbol.iterator function implicitly:
console.log([...cube]); // spread operator
for (var value of cube) { // for..of construct
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; // assumes all rows have same length
this[Symbol.iterator] = function() {
var row = -1;
var self = this;
// create a closure that returns an iterator
// on the captured row index
function createColIterator(currentRow) {
var col = -1;
var colIterator = {}
// column iterator implements iterable protocol
colIterator[Symbol.iterator] = function() {
return {next: function() {
col++;
if (col < self.numCols) {
// return raw value
return {
value: self.cubes[currentRow][col],
done: false
};
}
return {done: true};
}};
}
return colIterator;
}
return {next: function() {
row++;
if (row < self.numRows) {
// instead of a value, return another iterator
return {
value: createColIterator(row),
done: false
};
}
return {done: true}
}};
};
}
现在,我们可以使用嵌套迭代:
var cube = new Cubes();
// spread operator returns list of iterators,
// each of which can be spread to get values
var rows = [...cube];
console.log([...rows[0]]);
console.log([...rows[1]]);
console.log([...rows[2]]);
// use map to apply spread operator to each iterable
console.log([...cube].map(function(iterator) {
return [...iterator];
}));
for (var row of cube) {
for (var value of row) {
console.log(value);
}
}
需要注意的是我们自定义的迭代在所有情况下都不会像二维阵列那样表现出来;例如,我们还没有实现一个map()
函数。 This answer显示了如何实现一个生成器映射函数(see here用于迭代器和生成器之间的差异;同样,生成器是ES2016功能,而不是ES2015,因此如果使用babel编译,则需要change your babel presets)。
你的解决方案只适用于二维数组,但我发现了一种方法来循环通过任意数量的维数组:http://stackoverflow.com/a/15854485/975097 – 2013-07-20 22:15:12
@AndersonGreen OP特别寻找二维数组,因此上面的答案。感谢您的链接 - 希望它可以帮助有人在未来寻找类似的解决方案! – 2013-07-20 23:57:05
嗨,如何获得像'1,4,7','1,4,8','1,4,9','1,5,7','1,5,8'的结果...... – Bharadwaj 2013-08-01 11:26:09