gpt4 book ai didi

javascript - 如何简化和加速_.each?

转载 作者:塔克拉玛干 更新时间:2023-11-02 22:34:51 24 4
gpt4 key购买 nike

原生 Array.prototype.forEach() 非常慢。我不知道为什么。另外,我不知道为什么在Underscore.js中实现的 _.each()。我认为人们通常认为,如果它在库中,或者它是由浏览器实现的,那么它是正确的/有效的,直到被证明不正确/有效。

证明如下:

http://jsperf.com/native-vs-implmented-0

如果我们简单地从 underscore, _.each 中删除 native 调用,我们得到:

  var each = _.each = _.forEach = function(obj, iterator, context) {
if (obj == null) return;
if (obj.length === +obj.length) {
for (var i = 0, l = obj.length; i < l; i++) {
if (iterator.call(context, obj[i], i, obj) === breaker) return;
}
} else {
for (var key in obj) {
if (_.has(obj, key)) {
if (iterator.call(context, obj[key], key, obj) === breaker) return;
}
}
}
};

我也打算询问下划线团队,但我想确认我没有遗漏任何明显的东西。

这是可以提高性能的有效缩减吗?性能下降是希望有一天它会更快吗?这种减少是否可以在不丢失有用功能的情况下提高性能?

最佳答案

看看Lo-Dash .作者做了很多工作来研究这些性能问题,尤其是在 this blog post 中。和 this video .

如果性能是您的目标,那么您最好编写自己的迭代器,该迭代器只执行您需要的操作,而不会执行其他操作——那么它的性能应该会非常好。例如,在许多情况下,您只需要数组元素而不需要索引。您绝对不需要使用 .call() 将数组元素作为 this 传递给回调,因为它也是作为命名参数传递的。你真的需要让 return false; 在回调中终止循环吗?我不记得我最后一次用它了。所以它可以像这样简单:

function eachElement( array, callback ) {
for( var i = 0, n = array.length; i < n; ++i ) {
callback( array[i] );
}
}

在速度方面很难超越它。

当你需要索引时,你可以有一个单独的版本:

function eachElementAndIndex( array, callback ) {
for( var i = 0, n = array.length; i < n; ++i ) {
callback( array[i], i );
}
}

你可以使用更短的函数名;为了清楚起见,我只是在这里使用了这些长名称。结果可能是 eachElementAndIndex() 足够快,因此您可以调用它 each() 并完成它。

值得注意的是,@YuryTarabanko在上面的评论中指出,这些简化的迭代器不符合 Array.prototype.forEach() 的规范。除了不将数组元素作为 this 传递并且不将整个数组作为第三个参数传递之外,它们不检查丢失的元素并将为 0 中的每个数组索引调用回调array.length - 1 而不管数组元素是否实际存在。例如。

其实Underscore.js的_.each()在这方面是不一致的。当它回退到 Array.prototype.forEach() 时,它会跳过缺失的元素,但当它使用自己的 for 循环时,它会包含它们。

尝试转到 underscorejs.org并将其粘贴到 Chrome 控制台中:

function eachElementAndIndex( array, callback ) {
for( var i = 0, n = array.length; i < n; ++i ) {
callback( array[i], i );
}
}

function log( e, i ) {
console.log( i + ':', e );
}

var array = [];
array[2] = 'two';

console.log( 'eachElementAndIndex():' );
eachElementAndIndex( array, log );

console.log( '_.each() using native .forEach():' );
_.each( array, log );

console.log( '_.each() using its own loop:' );
var saveForEach = Array.prototype.forEach;
delete Array.prototype.forEach;
_.each( array, log );
Array.prototype.forEach = saveForEach;

console.log( 'Done' );

它记录:

eachElementAndIndex():
0: undefined
1: undefined
2: two
_.each() using native .forEach():
2: two
_.each() using its own loop:
0: undefined
1: undefined
2: two
Done

在许多(可能是大多数)情况下,缺少元素并不重要。您正在使用您创建的数组或 JSON 数组,并且您知道它没有任何缺失的元素。特别是对于 JSON 数组,这从来都不是问题,因为 JSON 没有办法生成缺少元素的数组。 JSON 数组可以有 null 元素,但 `.forEach() 像其他任何元素一样包含这些元素。

只要您的简化迭代器执行您想要的操作并且未命名为 Array.prototype.forEach,您就不必担心它会满足您自己以外的任何规范。但是,如果您确实需要跳过丢失的数组元素,请在您自己的代码中考虑到这一点或使用标准的 .forEach()

此外,为了进一步简化您正在查看的 Underscore 代码,因为我们正在谈论 .forEach(),这意味着我们只在谈论 _.each() 的 Array 部分,而不是 Object 部分。所以真正感兴趣的代码路径是这样的:

  var each = _.each = _.forEach = function(obj, iterator, context) {
if (obj == null) return;
if (obj.length === +obj.length) {
for (var i = 0, l = obj.length; i < l; i++) {
if (iterator.call(context, obj[i], i, obj) === breaker) return;
}
}
};

关于javascript - 如何简化和加速_.each?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17457171/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com