Javascript / angular - 使用forEach向后循环数组

时间:2020-12-05 21:22:01

Is there a way to loop backwards through an array using forEach (not any other kind of loop, I know how to do with with a for / standard ways) and without actually reversing the array itself?

有没有办法使用forEach向后循环数组(不是任何其他类型的循环,我知道如何使用for /标准方法)并且实际上没有反转数组本身?

3 个解决方案

#1


13  

var arr = [1, 2, 3];

arr.slice().reverse().forEach(function(x) {
    console.log(x);
})

will print:

将打印:

3
2
1

arr will still be [1, 2, 3], the .slice() creates a shallow copy.

arr仍然是[1,2,3],.slice()创建一个浅表副本。

#2


2  

No, forEach only processes forward through the array. So you'd have to do something else, which you've said in your question was out of scope.

不,forEach只通过数组进行处理。所以你必须做一些其他事情,你在问题中说过的事情超出了范围。

I can think of two options which just use precursors to using forEach (so, they don't use a for loop or other kind of loop). I don't know if those would be out of scope or not, so here they are:

我可以想到两个选项只使用前驱来使用forEach(因此,它们不使用for循环或其他类型的循环)。我不知道这些是否超出范围,所以这里是:

  1. Copy the array and reverse the copy, then use forEach on it

    复制数组并反转副本,然后在其上使用forEach

  2. Use Object.keys to get the indexes, reverse that, then use forEach on it (which will loop through the indexes, not the values, but then we can look them up)

    使用Object.keys获取索引,反转它,然后在其上使用forEach(它将遍历索引,而不是值,但我们可以查找它们)

Here's #1:

这是#1:

slice copies the array (shallow copy, so not likely to be expensive), then we reverse it, then forEach:

slice复制数组(浅拷贝,所以不太可能是昂贵的),然后我们反转它,然后forEach:

var a = ['one', 'two', 'three'];
a.slice().reverse().forEach(function(entry) {
    snippet.log(entry);
});
snippet.log("Proof that a is not, itself, reversed: " +
            JSON.stringify(a));
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

Here's #2:

这是#2:

We use Object.keys to get the array indices (using filter if you store non-element properties in your arrays), reverse that, and then loop through the result:

我们使用Object.keys来获取数组索引(如果在数组中存储非元素属性,则使用过滤器),反过来,然后遍历结果:

var a = ['one', 'two', 'three'];
Object.keys(a).reverse().forEach(function(index) {
    snippet.log(a[index]);
});
snippet.log("Proof that a is not, itself, reversed: " +
            JSON.stringify(a));
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>


Side note: Here's what I mean about using filter if you have non-element properties on your array:

旁注:如果您的数组上有非元素属性,那么我的意思是使用过滤器:

var a = ['one', 'two', 'three'];
a.nonElementProperty = "foo";
Object.keys(a).filter(function(name) {
  return String(+name) === name;
}).reverse().forEach(function(index) {
    snippet.log(a[index]);
});
snippet.log("Proof that a is not, itself, reversed: " +
            JSON.stringify(a));
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

#3


2  

As yet the browsers do not seem to have optimised the Array.forEach function. With not much effort you can write a simple polyfill that out performs the Array.forEach method by at least 10 to 1.

到目前为止,浏览器似乎还没有优化Array.forEach功能。通过不费力气,您可以编写一个简单的polyfill,它执行Array.forEach方法至少10比1。

So you can create your own Array.revEach and have it outperform the native Array.forEach, thought I hope that the browsers address the very slow performance of Array.forEach soon and make the need to polyfill actual existing methods not necessary.

因此,您可以创建自己的Array.revEach并使其优于本机Array.forEach,我希望浏览器能够很快解决Array.forEach的非常慢的性能,并且需要填充实际现有的方法,而不是必需的。

For Array.revEach out performs Array.forEach running 17 times faster on "Chrome 46.0.2490.22 beta-m"

对于Array.revEach,在“Chrome 46.0.2490.22 beta-m”上执行运行速度快17倍的Array.forEach

if (Array.prototype.revEach === undefined) { 
    Object.defineProperty(Array.prototype, 'revEach', { 
        writable : false,
        enumerable : false,
        configurable : false,
        value : function (func) {
            var i;
            var len = this.length-1;
            for (i = len; i >= 0; i--) {
                func(this[i], i, this);
            }
        }
    });
}

Just to add the actual official polyfill modified to reverse. Comments show my changes.

只是添加实际的官方polyfill修改为反向。评论显示我的变化。

// Production steps of ECMA-262, Edition 5, 15.4.4.18
// Reference: http://es5.github.io/#x15.4.4.18
// Modified by Blindman67 to revEach
if (!Array.prototype.revEach) {   // name changed
  Array.prototype.revEach = function(callback, thisArg) { // name changed
    var T;  // k defined where len was
    if (this == null) {
      throw new TypeError(' this is null or not defined');
    }
    var O = Object(this);
    var k = (O.length >>> 0)-1;  // set k (counter) ToUint32
                                 // len var removed
    if (typeof callback !== "function") {
      throw new TypeError(callback + ' is not a function');
    }
    if (arguments.length > 1) {
      T = thisArg;
    }
    while (k >= 0) {  // reverse condition
      var kValue;
      if (k in O) {
        kValue = O[k];
        callback.call(T, kValue, k, O);
      }
      k--;  // dec counter
    }
  };
}

#1


13  

var arr = [1, 2, 3];

arr.slice().reverse().forEach(function(x) {
    console.log(x);
})

will print:

将打印:

3
2
1

arr will still be [1, 2, 3], the .slice() creates a shallow copy.

arr仍然是[1,2,3],.slice()创建一个浅表副本。

#2


2  

No, forEach only processes forward through the array. So you'd have to do something else, which you've said in your question was out of scope.

不,forEach只通过数组进行处理。所以你必须做一些其他事情,你在问题中说过的事情超出了范围。

I can think of two options which just use precursors to using forEach (so, they don't use a for loop or other kind of loop). I don't know if those would be out of scope or not, so here they are:

我可以想到两个选项只使用前驱来使用forEach(因此,它们不使用for循环或其他类型的循环)。我不知道这些是否超出范围,所以这里是:

  1. Copy the array and reverse the copy, then use forEach on it

    复制数组并反转副本,然后在其上使用forEach

  2. Use Object.keys to get the indexes, reverse that, then use forEach on it (which will loop through the indexes, not the values, but then we can look them up)

    使用Object.keys获取索引,反转它,然后在其上使用forEach(它将遍历索引,而不是值,但我们可以查找它们)

Here's #1:

这是#1:

slice copies the array (shallow copy, so not likely to be expensive), then we reverse it, then forEach:

slice复制数组(浅拷贝,所以不太可能是昂贵的),然后我们反转它,然后forEach:

var a = ['one', 'two', 'three'];
a.slice().reverse().forEach(function(entry) {
    snippet.log(entry);
});
snippet.log("Proof that a is not, itself, reversed: " +
            JSON.stringify(a));
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

Here's #2:

这是#2:

We use Object.keys to get the array indices (using filter if you store non-element properties in your arrays), reverse that, and then loop through the result:

我们使用Object.keys来获取数组索引(如果在数组中存储非元素属性,则使用过滤器),反过来,然后遍历结果:

var a = ['one', 'two', 'three'];
Object.keys(a).reverse().forEach(function(index) {
    snippet.log(a[index]);
});
snippet.log("Proof that a is not, itself, reversed: " +
            JSON.stringify(a));
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>


Side note: Here's what I mean about using filter if you have non-element properties on your array:

旁注:如果您的数组上有非元素属性,那么我的意思是使用过滤器:

var a = ['one', 'two', 'three'];
a.nonElementProperty = "foo";
Object.keys(a).filter(function(name) {
  return String(+name) === name;
}).reverse().forEach(function(index) {
    snippet.log(a[index]);
});
snippet.log("Proof that a is not, itself, reversed: " +
            JSON.stringify(a));
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

#3


2  

As yet the browsers do not seem to have optimised the Array.forEach function. With not much effort you can write a simple polyfill that out performs the Array.forEach method by at least 10 to 1.

到目前为止,浏览器似乎还没有优化Array.forEach功能。通过不费力气,您可以编写一个简单的polyfill,它执行Array.forEach方法至少10比1。

So you can create your own Array.revEach and have it outperform the native Array.forEach, thought I hope that the browsers address the very slow performance of Array.forEach soon and make the need to polyfill actual existing methods not necessary.

因此,您可以创建自己的Array.revEach并使其优于本机Array.forEach,我希望浏览器能够很快解决Array.forEach的非常慢的性能,并且需要填充实际现有的方法,而不是必需的。

For Array.revEach out performs Array.forEach running 17 times faster on "Chrome 46.0.2490.22 beta-m"

对于Array.revEach,在“Chrome 46.0.2490.22 beta-m”上执行运行速度快17倍的Array.forEach

if (Array.prototype.revEach === undefined) { 
    Object.defineProperty(Array.prototype, 'revEach', { 
        writable : false,
        enumerable : false,
        configurable : false,
        value : function (func) {
            var i;
            var len = this.length-1;
            for (i = len; i >= 0; i--) {
                func(this[i], i, this);
            }
        }
    });
}

Just to add the actual official polyfill modified to reverse. Comments show my changes.

只是添加实际的官方polyfill修改为反向。评论显示我的变化。

// Production steps of ECMA-262, Edition 5, 15.4.4.18
// Reference: http://es5.github.io/#x15.4.4.18
// Modified by Blindman67 to revEach
if (!Array.prototype.revEach) {   // name changed
  Array.prototype.revEach = function(callback, thisArg) { // name changed
    var T;  // k defined where len was
    if (this == null) {
      throw new TypeError(' this is null or not defined');
    }
    var O = Object(this);
    var k = (O.length >>> 0)-1;  // set k (counter) ToUint32
                                 // len var removed
    if (typeof callback !== "function") {
      throw new TypeError(callback + ' is not a function');
    }
    if (arguments.length > 1) {
      T = thisArg;
    }
    while (k >= 0) {  // reverse condition
      var kValue;
      if (k in O) {
        kValue = O[k];
        callback.call(T, kValue, k, O);
      }
      k--;  // dec counter
    }
  };
}