Originally published on php-to-js.learnio.dev — part of the PHP to JavaScript course. View this lesson on the original site.

Chain small functions over arrays instead of manual loops

PHP gives you array_map, array_filter, and array_reduce. Laravel adds Collection::map, filter, and reduce. JavaScript puts the same ideas on every array as methods you can chain.

PHP habit

<?php
$orders = [
    ['id' => 1, 'total' => 50, 'status' => 'paid'],
    ['id' => 2, 'total' => 120, 'status' => 'pending'],
    ['id' => 3, 'total' => 30, 'status' => 'paid'],
];

$paid = array_filter($orders, fn ($o) => $o['status'] === 'paid');
$ids = array_map(fn ($o) => $o['id'], $paid);
$sum = array_reduce($paid, fn ($carry, $o) => $carry + $o['total'], 0);
// Laravel style
$sum = collect($orders)
    ->where('status', 'paid')
    ->sum('total');

JavaScript equivalent

const orders = [
  { id: 1, total: 50, status: 'paid' },
  { id: 2, total: 120, status: 'pending' },
  { id: 3, total: 30, status: 'paid' },
];

const paidIds = orders
  .filter((o) => o.status === 'paid')
  .map((o) => o.id);

const revenue = orders
  .filter((o) => o.status === 'paid')
  .reduce((sum, o) => sum + o.total, 0);
PHP JavaScript Role
array_map .map() Transform each element
array_filter .filter() Keep elements that pass a test
array_reduce .reduce() Fold to one value

map always returns an array of the same length. filter may shorten the array. reduce can return any type if you choose.

flowchart LR
  A[orders] --> B[filter paid]
  B --> C[map / transform]
  C --> D[reduce to total]

Callback shape

array.map((item, index, wholeArray) => { ... });
array.filter((item, index, wholeArray) => { ... });
array.reduce((carry, item, index, wholeArray) => { ... }, initial);

The first argument to reduce is the accumulator (like $carry in PHP). Always pass an initial value when the result type matters (e.g. 0 for sums, [] for building lists).

Failure mode: map when you mean filter

map that returns null for skipped items still leaves holes in length unless you filter afterwards. Prefer .filter() then .map().

Try it

Use the amber Try it panel below. Click Run.

const orders = [
  { id: 1, total: 50, status: 'paid' },
  { id: 2, total: 120, status: 'pending' },
  { id: 3, total: 30, status: 'paid' },
];

const paidIds = orders.filter((o) => o.status === 'paid').map((o) => o.id);
const revenue = orders
  .filter((o) => o.status === 'paid')
  .reduce((sum, o) => sum + o.total, 0);

console.log('paid ids', paidIds);
console.log('revenue', revenue);

Expect paid ids [1, 3] and revenue 80.

From PHP to JavaScript — Control Flow, Functions, and Scope