这两个不受欢迎的函数将改善您处理JavaScript数组数据的方式

Stupidity, outrage, vanity, cruelty, iniquity, bad faith, falsehood - we fail to see the whole array when it is facing in the same direction as we - Jean Rostand

愚蠢,愤怒,虚荣,残忍,罪孽,恶意,虚假-当与我们面对相同方向时,我们无法看到整个阵列-Jean Rostand

JavaScript has come a long way, it's progressively evolving at a compelling rate and winning an army of followers by the day. The modern JavaScript developer is arguably grappling with increased complexity than a few years ago, but is more armed with better native language features, a solid tooling ecosystem and a vibrant community.

JavaScript已经走了很长一段路,它以令人信服的速度不断发展,并每天赢得大量追随者。 可以说,现代JavaScript开发人员正比几年前更加复杂,但是拥有更好的本地语言功能,强大的工具生态系统和充满活力的社区。

介绍 ( Introduction )

ES5 and ES6 brought a ton of improvements to JavaScript, including better ways of working with a collection of data expressed as arrays. While the language has significantly improved support for declarative data manipulation on arrays, and modern browser support for them continue to be great, JavaScript developers are only adopting a limited subset of array capabilities - generally excluding those that should further improve how they manipulate arrays, and potentially give them performance gains.

ES5和ES6对JavaScript进行了大量改进,包括更好的处理以数组表示的数据集合的方法。 虽然该语言已大大改善了对数组中声明性数据操作的支持,并且现代浏览器对它们的支持仍然很大,但是JavaScript开发人员仅采用了有限的数组功能子集-通常不包括那些应进一步改善数组操作方式的功能,并且潜在地提高他们的表现。

Related Reading:

相关阅读:

杰出JavaScript数组函数 ( The Prominent JavaScript Array Functions )

Usage of .map(), .filter(), and .reduce() are very common. For the purpose of this article (and posterity if you don't mind), lets call these three functons MFR.

的使用.map() .filter().reduce()是很常见的。 出于本文的目的(如果您不介意,则为后代),我们将这三个函数称为MFR

They have gained more prominence over the other functions for manipulating array data in javascript. The very curious side of me would love to dig into this phenomenom to demonstrate beyond any doubt that this is the case, and try to see what reasons or predisposing factors I can establish.

与其他用于处理javascript中的数组数据的功能相比,它们更加突出。 我非常好奇的一面希望深入研究这一现象,以毫无疑问地证明情况确实如此,并尝试了解我可以建立哪些原因或诱发因素。

For instance, I would have loved to examine a number of open source repositories, run the codebases through some static analysis tool (not too hard to build with ASTs) and compare the adoption of various array manipulation functions across the codebases. If I ever make out the time to do this, I will definitely publish my findings.

例如,我本来希望检查许多开放源代码存储库,通过一些静态分析工具运行代码库(用AST很难构建),并比较各种代码库中采用的各种数组操作功能。 如果我有时间这样做,我一定会发表我的发现。

In the meantime, I did two simple things to help validate my hypothesis, and so far, they seem accurate.

同时,我做了两个简单的事情来帮助验证我的假设,到目前为止,它们似乎是正确的。

Google Trends show more interest in MFR

Google趋势MFR表现出更多兴趣

Google Search also show that search queries for MFR produce far more results.

Google搜索还显示,针对MFR的搜索查询产生的结果要多得多。

Search results for .filter() are as much as over 74M! This is 99.97% higher than results for .every(), and 99.98% higher than results for .some()!

.filter()搜索结果多达74M! 这比.every()结果高99.97%,比的结果高99.98%。 some()

This means people are talking, writing and teaching more MFR, creating more interests which is resulting in more searches, and ultimately more usage over time.

这意味着人们正在谈论,写作和教学更多的MFR ,产生了更多的兴趣,这导致了更多的搜索,最终随着时间的流逝而更多地使用。

Are these the only or best ways to manipulate data in Javascript arrays these days?

这些天是在Javascript数组中操作数据的唯一或最佳方法吗?

使用.some()更多思想输入.every()JavaScript数组对话 ( Enter .every() JavaScript Array Conversation with .some() More Thought )

JavaScript developers have probably been implicitly conditioned to limit computations on arrays to iteration (.forEach) and transformation (.map, .filter, .reduce - a.k.a MFR) operations. Hence not letting them see where more .some() and .every() should easily come in.

JavaScript开发人员可能已经隐式地将数组的计算限制为迭代(.forEach)和转换(.map,.filter,.reduce-aka MFR )操作。 因此,不要让他们看到更多的.some().every()应该从何而来。

The biggest problem here (and likely an anti-pattern) is how I believe developers unknowingly coerce computations that should naturally be done with .some() or .every() into MFR , especially a sequence of .filter() followed by a .reduce().

这里最大的问题(很可能是反模式)是我相信开发人员如何在不知不觉中将自然应该使用.some().every()完成的计算强制转换为MFR ,尤其是.filter()后跟一个。 reduce()

Almost every usage of MFR where you should be exiting early and not combing through the entire collection, is a prime candidate for .some() or .every() - because they both short-circuit and exit the array iteration as early as possible, instead of aimlesly running till the end and potentially wasting compute resources.

您应该提早退出而不是梳理整个集合的MFR几乎所有用法都是.some().every()的主要候选者-因为它们都会短路并尽可能早地退出数组迭代,而不是漫无目的地跑到最后并可能浪费计算资源。

In a time when we are building more complex apps and shipping more bytes to the client, resulting in significant overhead to parse Javascript (see TTI), anything we can do to have 3 iterations (due to short-circuit) instead of 30 - especially on mobile, is highly welcome.

在我们构建更复杂的应用程序并向客户端发送更多字节,从而导致解析Javascript(请参阅TTI )产生大量开销的时候,我们可以做的任何事情都需要3次迭代(由于短路)而不是30次迭代-特别是在移动设备上,非常受欢迎。

Array.prototype.every() ( Array.prototype.every() )

The every() method allows us establish if every element within an array meets a certain reqirement. It stops further evaluating the array (short circuit) the first time it finds an element that does not satisfy the given requirement.

every()方法允许我们确定数组中的每个元素是否满足一定要求。 第一次发现不满足给定要求的元素时,它将停止进一步评估阵列(短路)。

The every method executes the provided callback function once for each element present in the array until it finds one where callback returns a falsy value. If such an element is found, the every method immediately returns false. Otherwise, if callback returns a truthy value for all elements, every returns true. callback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values.This method returns true for any condition put on an empty array. -MDN

每个方法都会对数组中存在的每个元素执行一次提供的回调函数,直到找到一个回调返回虚假值的函数为止。 如果找到了这样的元素,那么every方法将立即返回false。 否则,如果callback为所有元素返回真实值,则每个返回true。 仅对具有分配值的数组索引调用回调; 对于已删除的索引或从未分配过索引的索引,不会调用它。对于在空数组上放置的任何条件,此方法返回true。 -MDN

Array.prototype.some() ( Array.prototype.some() )

The some() method allows us establish if some (at least one) elements within an array meets a certain requirement. It stops further evaluating the array (short circuit) the first time it finds an alement that does satisfy the given requirement.

some()方法允许我们确定数组中的某些 (至少一个)元素是否满足特定要求。 第一次找到确实满足给定要求的元件时,它将停止进一步评估阵列(短路)。

some() executes the callback function once for each element present in the array until it finds one where callback returns a truthy value (a value that becomes true when converted to a Boolean). If such an element is found, some() immediately returns true. Otherwise, some() returns false. callback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values.This method returns false for any condition put on an empty array. - MDN

some()对数组中存在的每个元素执行一次回调函数,直到找到一个回调返回真值(转换为布尔值的值)的值为止。 如果找到了这样的元素,some()将立即返回true。 否则,some()返回false。 仅对具有分配值的数组索引调用回调; 对于已删除的索引或从未分配过索引的索引,不会调用它。对于在空数组上放置的任何条件,此方法返回false。 -MDN

一个例子,两种情况 ( One Example, Two Scenarios )

You have been asked to write a simple add() function to add a bunch of integers. The function should expect to be given any number of integers to be added and it should return their sum after computing the addition

您被要求编写一个简单的add()函数来添加一堆整数。 该函数应该期望给出要添加的任意数量的整数,并且在计算加法后应返回它们的总和

场景一 (Scenario One)

If the add() function is given mixed input (e.g integers, floats, undefined, strings, e.t.c), it should proceed with just the integers and return the sum from adding them. We could implement our add() function this way:

如果给add()函数提供了混合输入(例如,整数,浮点数,未定义,字符串等),则应仅对整数进行处理,并从相加后返回总和。 我们可以这样实现add()函数:

const add = (...entries) => {
  return entries
    .filter(Number.isInteger)
    .reduce((sum, int) => {
      return sum + int;
    }, 0);
};

Since this scenario expects the add() function to compute the sum from whatever integers exists within the given inputs, one might implement the function like it is above. We first use .filter() to extract only the integers and then compute the sum with a .reduce(). The .filter() operation will however iterate over the entire array even if there are no integers within it. Quite wasteful.

由于这种情况要求add()函数根据给定输入中存在的任何整数来计算总和,因此可以像上面那样实现该函数。 我们首先使用.filter()只提取整数,然后计算用的总和.reduce() 但是,即使内部没有整数, .filter()操作也会遍历整个数组。 很浪费。

One can also argue that we can get a better solution like this below

也可以说我们可以在下面找到更好的解决方案

const add = (...entries) => {
  return entries.reduce((sum, entry) => {
    if(Number.isInteger(entry)) {
      return sum + entry;
    }
    return sum;
  }, 0);
};

This take on the add() is a little better because, unlike the first one that iterates to identify valid data and then further iterates to compute the result based on the valid data, now there is just one block of iteration, although we are still running through to the end of the array even if there might be no integers within it.

add()做法要好一些,因为与第一个迭代以识别有效数据然后进一步迭代以基于有效数据计算结果的方法不同,现在尽管只有一个迭代块,但仍然一直运行到数组末尾,即使其中可能没有整数。

输入.some() (Enter .some())

We need a way to first tell if the gathered inputs have at least one integer. Truth is, since we are trying to find the sum from the inputs, we actually need at least two integers in there. So we will proceed to reduce the inputs to the sum of her integers if we can find two or more integers. Lets use .some() so ensure this contidion is met so we dont aimlessly run through a potentially large array

我们需要一种方法来首先判断收集的输入是否至少有一个整数。 事实是,由于我们试图从输入中查找总和,因此实际上我们至少需要两个整数。 因此,如果可以找到两个或多个整数,我们将继续将输入减少为她的整数之和。 让我们使用.some()以确保满足此条件,因此我们不会漫无目的地运行可能很大的数组

const add = (...entries) => {
  let theSum = 0;
  if(hasTwoOrMoreInts(entries)){
    // there are >= 2 integers, lets sum them
    theSum = entries.reduce((sum, entry) => {
      if(Number.isInteger(entry)) {
        return sum + entry;
      }
      return sum;
    }, 0);
  }
  return theSum;
};

So now, we have a condition that prevents the sum calculation unless we are sure there are two or more intergers. We are doing this with a hasTwoOrMoreInts() function which we will be creating below

因此,现在,我们有一个条件阻止总和的计算,除非我们确定存在两个或多个整数。 我们使用hasTwoOrMoreInts()函数来完成此操作,我们将在下面创建

const hasTwoOrMoreInts = (entries) => {
  let lastIndex = -1;
  let hasMinimumIntsCount = false;

  const hasAnInt = entries.some((entry, index) => {
    lastIndex = index;
    return Number.isInteger(entry);
  });

  if(hasAnInt === true) {
    // we've got one int, is there another?
    const hasMoreInts = entries.slice(lastIndex + 1).some(Number.isInteger);
    hasMinimumIntsCount = (hasMoreInts === true) && hasAnInt;
  }

  return hasMinimumIntsCount;
};

方案二 (Scenario Two)

If the add() function can receive mixed input (e.g integers, floats, undefined, strings, e.t.c) but needs to only proceed with computing the sum of the given inputs if all the inputs are integers, a common approach influenced by the prominence of MFR might look like this:

如果add()函数可以接收混合输入(例如,整数,浮点数,未定义,字符串等),但如果所有输入均为整数,则仅需继续计算给定输入的总和,则该通用方法会受到MFR可能如下所示:

const add = (...entries) => {
  let theSum = 0;
  const nonInts = entries.filter(entry => !Number.isInteger(entry));
  if(nonInts.length === 0) {  // are there non-ints?
    theSum = entries.reduce((sum, int) => {
      return sum + int;
    }, 0);
  }
  return theSum;
}

Again entries.filter(...) attempts to see if there are invalid inputs by iterating the entire entries array to gather every input that is not an integer. If there are no invalid inputs (nonInts.length === 0), we compute the sum with .reduce(...). This would have made sense if we needed the total number of all invalid inputs or all the inputs themselves. Otherwise, we should be looking for the very first invalid input and deciding what next from there.

entries.filter(...)再次尝试通过遍历整个entries数组以收集每个不是整数的输入来查看是否存在无效输入。 如果没有无效输入( nonInts.length === 0 ),则使用.reduce(...)计算总和。 如果我们需要所有无效输入的总数或所有输入本身的数量,这将很有意义。 否则,我们应该寻找第一个无效输入,然后确定接下来要输入的内容。

输入.every() (Enter .every())

Like .some(...), .every(..) will act on the least information necessary. In this case, once it finds an input that is not an integer, it will look no further (by exiting with a return of false) and allow us proceed with the next important thing. Let's see how .every() does this for us

.some(...).every(..)将对所需的最少信息起作用。 在这种情况下,一旦找到不是整数的输入,就不会再看了(通过返回false退出),并允许我们继续进行下一个重要的事情。 让我们看看.every()如何为我们做到这一点

const add = (...entries) => {
  let theSum = 0;
  const areAllInts = entries.every(Number.isInteger);
  if(areAllInts === true) {  // are these indeed all ints?
    theSum = entries.reduce((sum, int) => {
      return sum + int;
    }, 0);
  }
  return theSum;
};

Since entries.every(...) will return false as soon as it finds what is not an integer, we are able to exit further tests for invalid elements within entries, freeing up resources that might be needed to give a mobile user a smooth scrolling experience!

由于entries.every(...)一旦发现不是整数的整数,将立即返回false ,因此我们可以退出对entries无效元素的进一步测试,从而释放出可能需要的资源,以使移动用户更加流畅滚动体验!

一个更实际的例子 ( A More Practical Example )

I know you dont write add() functions that often in your coding life. So I thought to describe something you probably do a lot. Lets apply .every() and .some() to a hypothetical HTML form validation, shall we!

我知道您不会在代码编写过程中经常编写add()函数。 因此,我想描述一下您可能会做的很多事情。 让我们将.every().some()应用于假设HTML表单验证中吧!

We should attempt to submit the form only after all required data have been obtained and validated from the form. We equally want at least one of the optional data to be filled in.

仅在从表格中获取并验证了所有必需的数据后,我们才应尝试提交表格。 我们同样希望至少填写一个可选数据。

const requiredFields = Array.of(
  isFirstNameValid(),
  isLastNameValid(),
  isEmailValid(),
  isAboutMeValid()
);

const optionalFields = Array.of(
  isTwitterValueValid(),
  isFacebookValue(),
  isGoogleplusValueValue()
);

const isValid = (inputStatus) => inputStatus === true;

if(requiredFields.every(isValid) && optionalFields.some(isValid)) {
  // all required fields are valid
  // and at least one social media field is valid
  // lets proceed to submit the form now :D
} else {
    // lets tell the user we are serious here!
    // this will happen really fast since we are short-circuting 
    // with .some and .every above
}

As seen above, all the functions within Array.of() are doing the validation for specific form fields, and then return either true or false. Since Array.of() is a factory for constructing arrays from the parameters it is given (the validation functions in our case), this means optionalFields can eventually look like [true, false, false]. This way, if any value in requiredFields is false, or if none of optionalFields is true, we do not submit the form. The form submission is decided with the shortest path of execution.

如上所示, Array.of()中的所有函数都在对特定表单字段进行验证,然后返回truefalse 。 由于Array.of()是根据给定参数构造数组的工厂(在本例中为验证函数),因此这意味着optionalFields最终看起来可能像[true, false, false] 。 这样,如果requiredFields任何值为false,或者optionalFields任何一个都不为true,则我们不提交表单。 表单提交是通过最短的执行路径来决定的。

结论与展望 ( Conclusion & Going Forward )

This exploration helped reveal how prominent MFR have become. It also sheds light on why you should be more open minded when manipulating your arrays. This lets you see where other array methods outside MFR should be used instead.

这项探索帮助揭示了MFR的重要性 。 它还阐明了为什么在处理数组时应该更加开放的思想。 这样,您可以查看应在MFR之外使用其他数组方法的位置。

Below are possible scenarios to promote or adopt .some() or .every() over MFR in your Javascript codebase

以下是可能推广或采用的方案。 Java代码中MFR上的 some().every()

  1. A .filter() immediately followed by .forEach(), or .map(), or .reduce() or any chained combination involving them

    .filter()之后紧跟.forEach().map()或。 reduce()或涉及它们的任何链式组合
  2. A .filter() immediately followed by a condition examining the result of the invocation, and where the body of the condition contains a .forEach() , or .map(), or .reduce() or any chained combination involving them, acting on the result from the .filter()

    一个 。 filter()紧随其后的是一个条件,该条件检查调用的结果,并且条件的主体包含.forEach().map().reduce()或涉及它们的任何链式组合,并对它们起作用.filter()

For these and other relevant scenarios, you want to ask yourself if you should be exiting the checks (validation usually done with .filter()) as soon as possible, and see if you are better off with .some() or .every()

对于这些以及其他相关情况,您想问自己是否应该尽快退出检查(通常使用.filter()进行验证),并查看使用.some().every() .some()是否更好。 .every()

翻译自: https://scotch.io/tutorials/these-2-unpopular-functions-will-improve-how-you-manipulate-javascript-array-data

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值