Course outline · 0% complete

0/29 lessons0%

Course overview →

find, some, every

lesson 7-2 · ~9 min · 23/29

Asking questions of an array

Three more methods take an arrow that answers true or false, but instead of building arrays they answer questions:

  • find(test) → the first item that passes, or undefined if none do.
  • some(test)true if at least one item passes (Python's any).
  • every(test)true if all items pass (Python's all).

They shine on arrays of objects, which is how real data usually arrives:

const users = [
  { name: "Ada", age: 36 },
  { name: "Alan", age: 41 }
];

const alan = users.find(u => u.name === "Alan");   // the whole object

find hands you the object itself, so alan.age is 41. For simple membership checks on plain values, includes from lesson 4-2 is still the shortest tool.

One search and three group questions

find returns the whole matching object, while some and every answer yes-or-no questions about the group as a whole.

const users = [
  { name: "Ada", age: 36 },
  { name: "Alan", age: 41 },
  { name: "Grace", age: 85 }
];

const alan = users.find(u => u.name === "Alan");
console.log(alan.age);

console.log(users.some(u => u.age > 80));
console.log(users.every(u => u.age >= 18));
console.log(users.some(u => u.name === "Linus"));

Output

41
true
true
false

find handed back the entire Alan object, not his position and not his name, which is why alan.age works directly on the result.

The three boolean lines each read as a sentence about the array. At least one user is over 80, since Grace is 85. Every user is an adult, since the youngest is 36. And no user is named Linus, so some reports false. Both methods stop early when they can, so some quits at its first success and every quits at its first failure.

Finding a record and validating a whole list

Two different questions about one inventory. The first locates a specific record, and the second checks a rule against every record at once.

const items = [
  { name: "pen", qty: 12, price: 1.5 },
  { name: "ink", qty: 0, price: 9 },
  { name: "pad", qty: 4, price: 3 }
];

const out = items.find(i => i.qty === 0);
console.log(out.name);

console.log(items.every(i => i.price > 0));

Output

ink
true

The find call tests i.qty === 0 with strict equality, which matters for a quantity check, since filter-style loose comparisons would also treat an empty string or false as zero. Once the ink record comes back, out.name reaches into it like any other object.

The every call is a data-quality check of the kind that belongs at the edges of a program, right after data arrives. It answers true here because all three prices are above zero, and a single bad record would flip it to false and be worth investigating.

When find matches nothing

users.find(u => u.age > 200) matches nobody, and the call returns undefined.

That return value is the reason careful code checks the result before using it. Writing users.find(...).name on a miss becomes undefined.name, which throws TypeError: Cannot read properties of undefined. The usual shapes for guarding it are an if around the use, or optional chaining from lesson 5-2 as found?.name, which quietly gives undefined instead of crashing.

It also helps to keep the empty results of these methods straight, because they are not the same value.

MethodResult when nothing matches
findundefined
filter[], an empty array
somefalse
everytrue, since no item broke the rule

That last row surprises people. every on an empty array is true, because the method reports whether any item failed, and an empty array has nothing that could fail.