javascript forEach方法有什么用(地图不能做)?

Joh*_*ino 89 javascript arrays foreach dictionary prototype

我在map和foreach中看到的唯一区别map是返回一个数组而forEach不是.但是,我甚至不理解方法的最后一行forEach" func.call(scope, this[i], i, this);".例如,是不是" this"和" scope"指的是同一个对象而不是this[i]并且i指的是循环中的当前值?

我在另一篇文章中注意到有人说" forEach当你想根据列表的每个元素做某事时使用.例如,你可能会在页面上添加内容.基本上,它非常适合你想要的"副作用".我不知道副作用是什么意思.

Array.prototype.map = function(fnc) {
    var a = new Array(this.length);
    for (var i = 0; i < this.length; i++) {
        a[i] = fnc(this[i]);
    }
    return a;
}

Array.prototype.forEach = function(func, scope) { 
    scope = scope || this; 
    for (var i = 0, l = this.length; i < l; i++) {
        func.call(scope, this[i], i, this); 
    } 
}
Run Code Online (Sandbox Code Playgroud)

最后,这些方法在javascript中是否有任何实际用途(因为我们不更新数据库),除了操纵这样的数字:

alert([1,2,3,4].map(function(x){ return x + 1})); //this is the only example I ever see of map in javascript.
Run Code Online (Sandbox Code Playgroud)

谢谢你的回复.

Ken*_*ler 93

mapforEach示例之间的本质区别在于forEach对原始数组元素进行操作,而map显式返回新数组作为结果.

随着forEach你正在采取一些行动 - 并且可选地改变 - 原始数组中的每个元素.该forEach方法运行您为每个元素提供的函数,但不返回任何内容(undefined).另一方面,map遍历数组,将函数应用于每个元素,并将结果作为新数组发出.

"副作用" forEach是原始数组正在改变."无副作用" map意味着,在惯用法中,原始数组元素不会改变; 新数组是原始数组中每个元素的一对一映射 - 映射变换是您提供的函数.

没有涉及数据库这一事实并不意味着您不必对数据结构进行操作,毕竟数据结构是任何语言编程的本质之一.至于你的上一个问题,你的数组不仅可以包含数字,还可以包含对象,字符串,函数等.

  • 回应过去:我恭敬地不同意.`.map()`创建一个新数组,并不会改变原始数组.你确实可以修改自己被映射的数组,但这至少是非惯用的,如果不是荒谬的话.`.EnEach()`虽然类似,但它将函数应用于每个元素,但始终返回`undefined`.尽管如此,OP还询问他自己的特定功能是否添加到阵列原型中; 过去没有ES5回来. (6认同)
  • 来自未来的说明:这个答案实际上是无稽之谈; `.map`可以做.forEach`可以做的所有事情(包括修改元素),它只返回一个从迭代器函数构造的新列表. (3认同)
  • 仍然没有"forEach"所做的事情你不能用`map`做.您可以根本不关心`map`的返回值,并且您有一个`forEach`.不同之处在于,对于您不希望根据结果创建新数组的任务,使用`map`是极其无效的.所以对于那些人,你使用`forEach`. (3认同)
  • @poke:..同样,你可以用一个简单的`for`循环做任何你需要的事情.我不同意"有效性"存在一些差异,但我也不认为有人认为一个人有一些魔法而另一个人无法以某种方式实现.事实上,有一件事就是`map`不能做:不返回数组.让JS不辜负其他语言的期望,就像`map`,`reduce`,`filter`等功能性收藏的行为一样.例如,你可以使用类似的构建块来实现`reduceRight`,但为什么不呢?只需使用`reduceRight`? (2认同)

nra*_*itz 65

这两种方法之间的主要区别是概念和风格:您可以使用forEach,当你想要做的事,以数组中的每个元素(做"和"什么是你引用的"副作用"的意思后,我想) ,而您map在想要复制和转换数组的每个元素时使用(而不更改原始元素).

因为无论mapforEach调用每个项目的功能在阵列中,且功能被用户定义的,几乎没有什么可以与一个而不是与其他做.虽然很丑,但是可​​以使用它map来就地修改数组和/或使用数组元素做一些事情:

var a = [{ val: 1 }, { val: 2 }, { val: 3 }];
a.map(function(el) {
    el.val++; // modify element in-place
    alert(el.val); // do something with each element
});
// a now contains [{ val: 2 }, { val: 3 }, { val: 4 }]
Run Code Online (Sandbox Code Playgroud)

但是你的意图更清晰,更明显forEach:

var a = [{ val: 1 }, { val: 2 }, { val: 3 }];
a.forEach(function(el) { 
    el.val++;
    alert(el.val);
});
Run Code Online (Sandbox Code Playgroud)

特别是如果像现实世界中的情况那样,el是一个有用的人类可读变量:

cats.forEach(function(cat) { 
    cat.meow(); // nicer than cats[x].meow()
});
Run Code Online (Sandbox Code Playgroud)

以同样的方式,您可以轻松地使用forEach新的数组:

var a = [1,2,3],
    b = [];
a.forEach(function(el) { 
    b.push(el+1); 
});
// b is now [2,3,4], a is unchanged
Run Code Online (Sandbox Code Playgroud)

但使用起来更清洁map:

var a = [1,2,3],
    b = a.map(function(el) { 
        return el+1; 
    });
Run Code Online (Sandbox Code Playgroud)

还要注意,因为map创建一个新数组,当你需要的只是迭代时,它可能会产生至少一些性能/内存命中,特别是对于大型数组 - 请参阅http://jsperf.com/map-foreach

至于为什么你想要使用这些函数,只要你需要在javascript中进行数组操作,它们就会很有用,这些(即使我们只是在浏览器环境中讨论javascript)经常是,几乎在任何时候您正在访问一个您未在代码中手动写下的数组.您可能正在处理页面上的DOM元素数组,或从AJAX请求中提取的数据,或者用户在表单中输入的数据.我遇到的一个常见示例是从外部API中提取数据,您可能希望map将数据转换为所需的格式,然后使用forEach迭代新数组以便将其显示给用户.

  • @chovy 我相信您应该根据是否要制作一系列结果来进行选择。`.map` 可以修改元素,是的,但它会创建一个你不需要的数组。您还应该考虑如何选择一个或另一个让读者猜测您是否有副作用 (2认同)

Jac*_*ang 16

投票的答案(来自Ken Redler)具有误导性.

副作用在计算机科学意味着一个功能/方法的一个属性改变全局状态[维基].从狭义上讲,这也可能包括从全球国家而不是从争论中读取.在命令式或OO编程中,大多数时候都会出现副作用.你可能在没有意识到的情况下使用它.

forEach和之间的显着差异mapmap分配内存并存储返回值,同时forEach抛弃它.有关更多信息,请参阅emca规范.

至于人们说forEach当你想要副作用时使用的原因是返回值forEach总是如此undefined.如果它没有副作用(不改变全局状态),那么该函数只是浪费cpu时间.优化编译器将消除此代码块并将其替换为最终值(undefined).

顺便说一下,应该注意JavaScript对副作用没有限制.你仍然可以修改里面的原始数组map.

var a = [1,2,3]; //original
var b = a.map( function(x,i){a[i] = 2*x; return x+1} );
console.log("modified=%j\nnew array=%j",a,b);
// output:
// modified=[2,4,6]
// new array=[2,3,4]
Run Code Online (Sandbox Code Playgroud)

  • 每隔几年回顾一下这个问题及其答案和评论总是很有趣的。JS 中 Map 的实现方式,在内存分配方面,是另一个不错的角度。 (2认同)

Sum*_*rve 6

这是一个意想不到的答案的漂亮问题.

以下是基于官方的描述Array.prototype.map().

没有什么forEach()可以做到这一点map()做不到.也就是说,map()是一个严格的超集forEach().

虽然map()通常用于创建新数组,但它可用于更改当前数组.以下示例说明了这一点:

var a = [0, 1, 2, 3, 4], mapped = null;
mapped = a.map(function (x) { a[x] = x*x*x; return x*x; });
console.log(mapped); // logs [0, 1, 4, 9, 16]  As expected, these are squares.
console.log(a); // logs [0, 1, 8, 27, 64] These are cubes of the original array!!
Run Code Online (Sandbox Code Playgroud)

在上面的例子中,a方便地设置a[i] === ii < a.length.即便如此,它也证明了它的强大功能map(),特别是它能够改变调用它的阵列.

注1:
官方描述暗示map()甚至可能改变调用它的数组的长度!但是,我看不到(很好)这样做的理由.

注2:
虽然map()map是超集forEach(),但是forEach()仍然应该在需要更改给定数组的地方使用.这使你的意图清晰.

希望这有帮助.

  • 实际上有一件事是forEach可以做的,地图不能做 - 不返回数组. (8认同)