DevToolBox免费
博客

JavaScript 数组方法速查表

14 分钟阅读作者 DevToolBox

JavaScript 数组自带 30 多个内置方法,是每个开发者每天都会用到的。但很容易混淆哪些方法会修改原数组、哪些返回新数组,也容易忘记 findfiltersome 之间的微妙区别。这份 JavaScript 数组方法速查表是一份全面的、值得收藏的参考,涵盖每个方法的可运行代码示例、输入/输出、Big-O 复杂度以及最新的 ES2023+ 新增方法。

使用我们的 JS/HTML 格式化工具格式化你的 JavaScript →

使用我们的 JSON 格式化工具验证 JSON 输出 →

1. 变异方法 vs 非变异方法

最常见的 bug 来源:一些数组方法会就地修改原数组(变异方法),而另一些返回新数组(非变异方法)。ES2023 为每个变异方法引入了不可变替代方案(toSortedtoReversedtoSplicedwith)。

// ========== MUTATING METHODS (modify original array) ==========
// push, pop, shift, unshift, splice, sort, reverse, fill, copyWithin

const arr = [1, 2, 3];
arr.push(4);          // arr is now [1, 2, 3, 4]
arr.reverse();        // arr is now [4, 3, 2, 1]
arr.sort();           // arr is now [1, 2, 3, 4]
console.log(arr);     // [1, 2, 3, 4] — original is modified!

// ========== NON-MUTATING METHODS (return new array) ==========
// map, filter, reduce, slice, concat, flat, flatMap,
// toSorted, toReversed, toSpliced, with (ES2023+)

const nums = [3, 1, 2];
const sorted = nums.toSorted();    // [1, 2, 3] — new array
console.log(nums);                 // [3, 1, 2] — original unchanged!

const doubled = nums.map(n => n * 2);  // [6, 2, 4]
console.log(nums);                      // [3, 1, 2] — still unchanged
// Quick reference table:
// ┌────────────────────┬─────────────────────────────────────────────┐
// │ Mutating           │ Non-Mutating Equivalent                    │
// ├────────────────────┼─────────────────────────────────────────────┤
// │ sort()             │ toSorted()          (ES2023)               │
// │ reverse()          │ toReversed()        (ES2023)               │
// │ splice()           │ toSpliced()         (ES2023)               │
// │ arr[i] = value     │ with(index, value)  (ES2023)               │
// │ push/pop           │ concat / slice(0,-1)                       │
// │ shift/unshift      │ slice(1) / [item, ...arr]                  │
// │ fill()             │ Array.from({length}, () => value)          │
// └────────────────────┴─────────────────────────────────────────────┘

2. 添加和删除元素

修改数组内容的核心方法:pushpopshiftunshift 和万能的 splice。这些方法都会修改原数组。

// push() — add to END, returns new length
const fruits = ['apple', 'banana'];
const len = fruits.push('cherry', 'date');
console.log(fruits); // ['apple', 'banana', 'cherry', 'date']
console.log(len);    // 4

// pop() — remove from END, returns removed element
const last = fruits.pop();
console.log(last);   // 'date'
console.log(fruits); // ['apple', 'banana', 'cherry']

// unshift() — add to START, returns new length
fruits.unshift('avocado');
console.log(fruits); // ['avocado', 'apple', 'banana', 'cherry']

// shift() — remove from START, returns removed element
const first = fruits.shift();
console.log(first);  // 'avocado'
console.log(fruits); // ['apple', 'banana', 'cherry']
// splice(start, deleteCount, ...items) — the Swiss Army knife
// Returns an array of removed elements

const arr = [1, 2, 3, 4, 5];

// Delete 2 elements starting at index 1
const removed = arr.splice(1, 2);
console.log(removed); // [2, 3]
console.log(arr);     // [1, 4, 5]

// Insert without deleting (deleteCount = 0)
arr.splice(1, 0, 'a', 'b');
console.log(arr);     // [1, 'a', 'b', 4, 5]

// Replace: delete 1 element and insert 2
arr.splice(2, 1, 'x', 'y');
console.log(arr);     // [1, 'a', 'x', 'y', 4, 5]

// Negative index: count from end
const arr2 = [1, 2, 3, 4, 5];
arr2.splice(-2, 1);   // remove element at index 3 (5-2)
console.log(arr2);    // [1, 2, 3, 5]

// Delete everything from index 2 onward
const arr3 = [1, 2, 3, 4, 5];
arr3.splice(2);
console.log(arr3);    // [1, 2]

3. 搜索数组

JavaScript 提供了六种搜索数组的方法。根据你需要的是元素本身索引还是布尔值来选择。

const users = [
  { id: 1, name: 'Alice', age: 30 },
  { id: 2, name: 'Bob', age: 25 },
  { id: 3, name: 'Charlie', age: 35 },
  { id: 4, name: 'Diana', age: 28 },
];

// find() — returns FIRST matching element (or undefined)
const bob = users.find(u => u.name === 'Bob');
console.log(bob); // { id: 2, name: 'Bob', age: 25 }

// findIndex() — returns INDEX of first match (or -1)
const idx = users.findIndex(u => u.age > 30);
console.log(idx); // 2 (Charlie)

// indexOf() — for primitives, strict equality (===)
const colors = ['red', 'green', 'blue', 'green'];
console.log(colors.indexOf('green'));      // 1 (first occurrence)
console.log(colors.indexOf('green', 2));   // 3 (search from index 2)
console.log(colors.indexOf('purple'));     // -1 (not found)

// includes() — returns boolean
console.log(colors.includes('blue'));  // true
console.log(colors.includes('pink'));  // false

// some() — returns true if ANY element passes the test
const hasAdult = users.some(u => u.age >= 30);
console.log(hasAdult); // true

// every() — returns true if ALL elements pass the test
const allAdults = users.every(u => u.age >= 18);
console.log(allAdults); // true
const allOver30 = users.every(u => u.age > 30);
console.log(allOver30); // false
// findLast() and findLastIndex() — ES2023, search from the END
const nums = [1, 5, 3, 8, 2, 7];

const lastOver4 = nums.findLast(n => n > 4);
console.log(lastOver4); // 7 (last element > 4)

const lastIdx = nums.findLastIndex(n => n > 4);
console.log(lastIdx);   // 5 (index of 7)

// Comparison: find vs findLast
console.log(nums.find(n => n > 4));     // 5 (first match)
console.log(nums.findLast(n => n > 4)); // 7 (last match)

// lastIndexOf() — for primitives, search from end
const letters = ['a', 'b', 'c', 'b', 'a'];
console.log(letters.lastIndexOf('b')); // 3
console.log(letters.lastIndexOf('b', 2)); // 1 (search up to index 2)

4. 使用 map 和 flatMap 转换

map() 通过对每个元素应用函数来创建新数组。flatMap() 先映射再展平一层——非常适合一对多转换。两者都不会修改原数组。

// map() — transform each element, returns new array
const nums = [1, 2, 3, 4, 5];

const doubled = nums.map(n => n * 2);
console.log(doubled); // [2, 4, 6, 8, 10]

const strings = nums.map(n => `Item ${n}`);
console.log(strings); // ['Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5']

// map with index
const indexed = nums.map((n, i) => ({ index: i, value: n }));
console.log(indexed);
// [{ index: 0, value: 1 }, { index: 1, value: 2 }, ...]

// Extract a property from objects
const users = [
  { name: 'Alice', score: 90 },
  { name: 'Bob', score: 85 },
  { name: 'Charlie', score: 92 },
];
const names = users.map(u => u.name);
console.log(names); // ['Alice', 'Bob', 'Charlie']

// Parse strings to numbers
const strs = ['1', '2', '3'];
const parsed = strs.map(Number);
console.log(parsed); // [1, 2, 3]
// ⚠️ Caution: ['1','2','3'].map(parseInt) gives [1, NaN, NaN]
// because parseInt receives (value, index) as (string, radix)
// flatMap() — map + flatten one level (great for 1-to-many)
const sentences = ['Hello World', 'Foo Bar Baz'];
const words = sentences.flatMap(s => s.split(' '));
console.log(words); // ['Hello', 'World', 'Foo', 'Bar', 'Baz']

// vs map + flat:
const wordsAlt = sentences.map(s => s.split(' ')).flat();
console.log(wordsAlt); // same result, but flatMap is more efficient

// Filter and map in one pass
const nums2 = [1, 2, 3, 4, 5, 6];
const evenDoubled = nums2.flatMap(n => n % 2 === 0 ? [n * 2] : []);
console.log(evenDoubled); // [4, 8, 12]

// Duplicate elements conditionally
const items = ['a', 'b', 'c'];
const duplicated = items.flatMap(x => [x, x]);
console.log(duplicated); // ['a', 'a', 'b', 'b', 'c', 'c']

// Expand nested tags
const posts = [
  { title: 'Post 1', tags: ['js', 'react'] },
  { title: 'Post 2', tags: ['css', 'html'] },
];
const allTags = posts.flatMap(p => p.tags);
console.log(allTags); // ['js', 'react', 'css', 'html']

5. 过滤数组

filter() 返回一个新数组,只包含通过测试函数的元素。它是 JavaScript 中最常被链式调用的方法之一。

// filter() — returns new array with elements that pass the test
const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

const evens = nums.filter(n => n % 2 === 0);
console.log(evens); // [2, 4, 6, 8, 10]

const greaterThan5 = nums.filter(n => n > 5);
console.log(greaterThan5); // [6, 7, 8, 9, 10]

// Filter objects by property
const products = [
  { name: 'Laptop', price: 999, inStock: true },
  { name: 'Phone', price: 699, inStock: false },
  { name: 'Tablet', price: 499, inStock: true },
  { name: 'Watch', price: 299, inStock: true },
];

const available = products.filter(p => p.inStock);
console.log(available.map(p => p.name));
// ['Laptop', 'Tablet', 'Watch']

const affordable = products.filter(p => p.price < 500 && p.inStock);
console.log(affordable);
// [{ name: 'Tablet', price: 499, inStock: true },
//  { name: 'Watch', price: 299, inStock: true }]

// Remove falsy values (null, undefined, 0, '', false, NaN)
const mixed = [0, 1, '', 'hello', null, undefined, false, true, NaN];
const truthy = mixed.filter(Boolean);
console.log(truthy); // [1, 'hello', true]

// Remove duplicates using filter + indexOf
const withDupes = [1, 2, 3, 2, 1, 4, 3, 5];
const unique = withDupes.filter((val, idx, arr) => arr.indexOf(val) === idx);
console.log(unique); // [1, 2, 3, 4, 5]
// Chaining filter with other methods
const orders = [
  { id: 1, total: 150, status: 'shipped' },
  { id: 2, total: 50, status: 'pending' },
  { id: 3, total: 300, status: 'shipped' },
  { id: 4, total: 75, status: 'cancelled' },
  { id: 5, total: 200, status: 'shipped' },
];

// Get total revenue from shipped orders over $100
const revenue = orders
  .filter(o => o.status === 'shipped')
  .filter(o => o.total > 100)
  .reduce((sum, o) => sum + o.total, 0);
console.log(revenue); // 650

// Get sorted names of shipped orders
const shippedIds = orders
  .filter(o => o.status === 'shipped')
  .map(o => o.id)
  .sort((a, b) => a - b);
console.log(shippedIds); // [1, 3, 5]

6. 归并数组

reduce() 是最通用的数组方法——它可以实现任何其他数组方法。它处理每个元素并累积一个结果。reduceRight() 从右到左工作。

// reduce(callback, initialValue)
// callback: (accumulator, currentValue, currentIndex, array) => newAccumulator

// ---- Sum ----
const nums = [1, 2, 3, 4, 5];
const sum = nums.reduce((acc, n) => acc + n, 0);
console.log(sum); // 15

// ---- Max ----
const max = nums.reduce((acc, n) => Math.max(acc, n), -Infinity);
console.log(max); // 5

// ---- Flatten nested arrays ----
const nested = [[1, 2], [3, 4], [5, [6, 7]]];
const flat = nested.reduce((acc, val) => acc.concat(val), []);
console.log(flat); // [1, 2, 3, 4, 5, [6, 7]]
// Note: for deep flattening, use .flat(Infinity)

// ---- Count occurrences ----
const words = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple'];
const counts = words.reduce((acc, word) => {
  acc[word] = (acc[word] || 0) + 1;
  return acc;
}, {});
console.log(counts);
// { apple: 3, banana: 2, cherry: 1 }
// ---- Group by property ----
const people = [
  { name: 'Alice', dept: 'Engineering' },
  { name: 'Bob', dept: 'Marketing' },
  { name: 'Charlie', dept: 'Engineering' },
  { name: 'Diana', dept: 'Marketing' },
  { name: 'Eve', dept: 'Design' },
];

const grouped = people.reduce((acc, person) => {
  const key = person.dept;
  if (!acc[key]) acc[key] = [];
  acc[key].push(person.name);
  return acc;
}, {});
console.log(grouped);
// {
//   Engineering: ['Alice', 'Charlie'],
//   Marketing: ['Bob', 'Diana'],
//   Design: ['Eve']
// }

// Modern alternative: Object.groupBy() (ES2024)
// const grouped = Object.groupBy(people, p => p.dept);

// ---- Build object from entries ----
const pairs = [['name', 'Alice'], ['age', 30], ['city', 'NYC']];
const obj = pairs.reduce((acc, [key, val]) => {
  acc[key] = val;
  return acc;
}, {});
console.log(obj); // { name: 'Alice', age: 30, city: 'NYC' }
// Modern alternative: Object.fromEntries(pairs)

// ---- Pipeline / compose functions ----
const pipeline = [
  (x) => x + 1,
  (x) => x * 2,
  (x) => x - 3,
];
const result = pipeline.reduce((val, fn) => fn(val), 5);
console.log(result); // ((5 + 1) * 2) - 3 = 9

// ---- reduceRight: process from right to left ----
const letters = ['a', 'b', 'c', 'd'];
const reversed = letters.reduceRight((acc, letter) => acc + letter, '');
console.log(reversed); // 'dcba'

7. 排序数组

sort() 就地排序数组并返回它。没有比较器时,元素会被转换为字符串并按 UTF-16 码点值排序。ES2023 添加了 toSorted() 作为非变异替代方案。

// ⚠️ Default sort converts to strings!
const nums = [10, 9, 2, 21, 3];
nums.sort();
console.log(nums); // [10, 2, 21, 3, 9] — WRONG! String comparison

// ✅ Numeric sort with comparator
const nums2 = [10, 9, 2, 21, 3];
nums2.sort((a, b) => a - b);       // ascending
console.log(nums2); // [2, 3, 9, 10, 21]

nums2.sort((a, b) => b - a);       // descending
console.log(nums2); // [21, 10, 9, 3, 2]

// Sort objects by property
const users = [
  { name: 'Charlie', age: 35 },
  { name: 'Alice', age: 25 },
  { name: 'Bob', age: 30 },
];

users.sort((a, b) => a.age - b.age);
console.log(users.map(u => u.name)); // ['Alice', 'Bob', 'Charlie']

// Sort by string property
users.sort((a, b) => a.name.localeCompare(b.name));
console.log(users.map(u => u.name)); // ['Alice', 'Bob', 'Charlie']
// toSorted() — ES2023, non-mutating sort
const original = [3, 1, 4, 1, 5];
const sorted = original.toSorted((a, b) => a - b);
console.log(sorted);   // [1, 1, 3, 4, 5]
console.log(original); // [3, 1, 4, 1, 5] — unchanged!

// Locale-aware sorting with localeCompare
const cities = ['Zürich', 'Amsterdam', 'Ångström', 'Berlin'];
cities.sort((a, b) => a.localeCompare(b, 'de'));
console.log(cities); // ['Amsterdam', 'Ångström', 'Berlin', 'Zürich']

// Sort with multiple criteria
const students = [
  { name: 'Alice', grade: 'A', score: 95 },
  { name: 'Bob', grade: 'A', score: 90 },
  { name: 'Charlie', grade: 'B', score: 85 },
  { name: 'Diana', grade: 'A', score: 95 },
];

students.sort((a, b) => {
  // First by grade (ascending)
  if (a.grade !== b.grade) return a.grade.localeCompare(b.grade);
  // Then by score (descending)
  if (a.score !== b.score) return b.score - a.score;
  // Then by name (ascending)
  return a.name.localeCompare(b.name);
});
console.log(students.map(s => s.name));
// ['Alice', 'Diana', 'Bob', 'Charlie']

// Stable sort: equal elements keep original order (guaranteed since ES2019)
const items = [
  { name: 'A', priority: 1 },
  { name: 'B', priority: 2 },
  { name: 'C', priority: 1 },
];
items.sort((a, b) => a.priority - b.priority);
// A and C both have priority 1; A stays before C (stable)
console.log(items.map(i => i.name)); // ['A', 'C', 'B']

8. 迭代:forEach vs for...of vs map

三种常见的数组迭代方式,各有不同的使用场景。选择正确的方式会影响可读性、性能以及使用 break/continue 的能力。

const fruits = ['apple', 'banana', 'cherry'];

// ---- forEach: for side effects, no return value ----
fruits.forEach((fruit, index) => {
  console.log(`${index}: ${fruit}`);
});
// 0: apple
// 1: banana
// 2: cherry
// ⚠️ Cannot use break/continue, returns undefined

// ---- for...of: supports break/continue, cleaner syntax ----
for (const fruit of fruits) {
  if (fruit === 'banana') continue;  // skip banana
  console.log(fruit);
}
// apple
// cherry

// Need index with for...of? Use entries()
for (const [index, fruit] of fruits.entries()) {
  console.log(`${index}: ${fruit}`);
}

// ---- map: when you need a new array ----
const upper = fruits.map(f => f.toUpperCase());
console.log(upper); // ['APPLE', 'BANANA', 'CHERRY']

// ---- Comparison summary ----
// ┌──────────────┬─────────────┬───────────────┬──────────────────┐
// │ Feature      │ forEach     │ for...of      │ map              │
// ├──────────────┼─────────────┼───────────────┼──────────────────┤
// │ Returns      │ undefined   │ N/A           │ new Array        │
// │ break/cont   │ ✗           │ ✓             │ ✗                │
// │ Chainable    │ ✗           │ ✗             │ ✓                │
// │ async/await  │ ✗ (tricky)  │ ✓             │ ✗ (use for...of) │
// │ Performance  │ Medium      │ Fast          │ Medium           │
// │ Use case     │ Side effects│ General loop  │ Transform array  │
// └──────────────┴─────────────┴───────────────┴──────────────────┘
// ⚠️ forEach does NOT work well with async/await
const urls = ['/api/1', '/api/2', '/api/3'];

// ❌ BAD: forEach fires all fetches in parallel, does not await
urls.forEach(async (url) => {
  const res = await fetch(url);  // Not actually awaited sequentially!
  console.log(res.status);
});

// ✅ GOOD: for...of with await for sequential execution
for (const url of urls) {
  const res = await fetch(url);
  console.log(res.status);  // Each request waits for the previous
}

// ✅ GOOD: Promise.all for parallel execution
const results = await Promise.all(
  urls.map(url => fetch(url).then(r => r.json()))
);
console.log(results);

9. 创建数组

JavaScript 中创建和初始化数组的多种方式,从字面量到工厂方法。

// Array literal (most common)
const arr = [1, 2, 3];

// Array.from() — create from array-like or iterable
const fromString = Array.from('hello');
console.log(fromString); // ['h', 'e', 'l', 'l', 'o']

const fromSet = Array.from(new Set([1, 2, 2, 3]));
console.log(fromSet); // [1, 2, 3]

// Array.from with mapping function (second argument)
const squares = Array.from({ length: 5 }, (_, i) => (i + 1) ** 2);
console.log(squares); // [1, 4, 9, 16, 25]

// Generate range: 0 to 9
const range = Array.from({ length: 10 }, (_, i) => i);
console.log(range); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

// Array.of() — creates array from arguments (vs Array constructor)
const a = Array.of(5);      // [5] — single element
const b = Array(5);          // [empty × 5] — 5 empty slots!
console.log(a); // [5]
console.log(b); // [empty × 5]

// fill() — fill all or part of array with a value (mutating)
const zeros = new Array(5).fill(0);
console.log(zeros); // [0, 0, 0, 0, 0]

// ⚠️ fill with objects shares the SAME reference
const bad = new Array(3).fill([]);
bad[0].push('oops');
console.log(bad); // [['oops'], ['oops'], ['oops']] — all same array!

// ✅ Use Array.from for unique objects
const good = Array.from({ length: 3 }, () => []);
good[0].push('ok');
console.log(good); // [['ok'], [], []] — independent arrays

// Spread operator — shallow copy
const original = [1, 2, 3];
const copy = [...original];
copy.push(4);
console.log(original); // [1, 2, 3] — unchanged
console.log(copy);     // [1, 2, 3, 4]

// structuredClone — deep copy (handles nested objects)
const deep = [{ a: 1 }, { b: [2, 3] }];
const deepCopy = structuredClone(deep);
deepCopy[1].b.push(4);
console.log(deep[1].b);     // [2, 3] — unchanged
console.log(deepCopy[1].b); // [2, 3, 4]

10. ES2023+ 新方法

ES2023(ES14)引入了六个新的数组方法,为现有的变异方法提供不可变替代方案。这些方法在所有现代浏览器和 Node.js 20+ 中都已支持。

// toSorted() — non-mutating sort
const nums = [3, 1, 4, 1, 5];
const sorted = nums.toSorted((a, b) => a - b);
console.log(sorted); // [1, 1, 3, 4, 5]
console.log(nums);   // [3, 1, 4, 1, 5] — unchanged

// toReversed() — non-mutating reverse
const arr = [1, 2, 3, 4, 5];
const reversed = arr.toReversed();
console.log(reversed); // [5, 4, 3, 2, 1]
console.log(arr);      // [1, 2, 3, 4, 5] — unchanged

// toSpliced() — non-mutating splice
const colors = ['red', 'green', 'blue'];
const newColors = colors.toSpliced(1, 1, 'yellow', 'purple');
console.log(newColors); // ['red', 'yellow', 'purple', 'blue']
console.log(colors);    // ['red', 'green', 'blue'] — unchanged

// with() — non-mutating index assignment
const letters = ['a', 'b', 'c', 'd'];
const updated = letters.with(2, 'X');
console.log(updated);  // ['a', 'b', 'X', 'd']
console.log(letters);  // ['a', 'b', 'c', 'd'] — unchanged

// with() supports negative indices
const last = letters.with(-1, 'Z');
console.log(last); // ['a', 'b', 'c', 'Z']
// findLast() — find from the end
const nums = [1, 2, 3, 4, 5, 6];
const lastEven = nums.findLast(n => n % 2 === 0);
console.log(lastEven); // 6

// findLastIndex() — find index from the end
const lastEvenIdx = nums.findLastIndex(n => n % 2 === 0);
console.log(lastEvenIdx); // 5

// Real-world: find last error in log entries
const logs = [
  { level: 'info', msg: 'Started' },
  { level: 'error', msg: 'Connection failed' },
  { level: 'info', msg: 'Retrying' },
  { level: 'error', msg: 'Timeout' },
  { level: 'info', msg: 'Connected' },
];

const lastError = logs.findLast(log => log.level === 'error');
console.log(lastError); // { level: 'error', msg: 'Timeout' }

// Chaining ES2023 methods (fully immutable pipeline)
const scores = [85, 92, 78, 95, 88, 70];
const topThree = scores
  .toSorted((a, b) => b - a)   // sort descending (immutable)
  .toSpliced(3);                // keep only first 3 (immutable)
console.log(topThree); // [95, 92, 88]
console.log(scores);   // [85, 92, 78, 95, 88, 70] — unchanged

11. 链式调用模式

方法链式调用是 JavaScript 数组真正闪光的地方。以下是将多个方法组合成干净、可读管道的实际模式。

// ---- Extract, transform, aggregate ----
const transactions = [
  { id: 1, type: 'sale', amount: 100, currency: 'USD' },
  { id: 2, type: 'refund', amount: 50, currency: 'USD' },
  { id: 3, type: 'sale', amount: 200, currency: 'EUR' },
  { id: 4, type: 'sale', amount: 150, currency: 'USD' },
  { id: 5, type: 'refund', amount: 30, currency: 'EUR' },
];

// Total USD sales revenue
const usdRevenue = transactions
  .filter(t => t.type === 'sale' && t.currency === 'USD')
  .map(t => t.amount)
  .reduce((sum, amount) => sum + amount, 0);
console.log(usdRevenue); // 250

// ---- Deduplicate, sort, format ----
const rawTags = ['React', 'vue', 'REACT', 'Angular', 'vue', 'Svelte'];
const cleanTags = [...new Set(rawTags.map(t => t.toLowerCase()))]
  .sort()
  .map(t => t.charAt(0).toUpperCase() + t.slice(1));
console.log(cleanTags); // ['Angular', 'React', 'Svelte', 'Vue']
// ---- Nested data extraction ----
const departments = [
  {
    name: 'Engineering',
    teams: [
      { name: 'Frontend', members: ['Alice', 'Bob'] },
      { name: 'Backend', members: ['Charlie', 'Diana'] },
    ],
  },
  {
    name: 'Design',
    teams: [
      { name: 'UX', members: ['Eve', 'Frank'] },
    ],
  },
];

// Get all member names across all departments and teams
const allMembers = departments
  .flatMap(dept => dept.teams)
  .flatMap(team => team.members)
  .sort();
console.log(allMembers);
// ['Alice', 'Bob', 'Charlie', 'Diana', 'Eve', 'Frank']

// ---- Paginate results ----
function paginate(array, page, pageSize) {
  return array.slice((page - 1) * pageSize, page * pageSize);
}

const items = Array.from({ length: 50 }, (_, i) => `Item ${i + 1}`);
console.log(paginate(items, 1, 10)); // ['Item 1', ..., 'Item 10']
console.log(paginate(items, 3, 10)); // ['Item 21', ..., 'Item 30']

// ---- Top N by score ----
const players = [
  { name: 'Alice', score: 850 },
  { name: 'Bob', score: 920 },
  { name: 'Charlie', score: 780 },
  { name: 'Diana', score: 950 },
  { name: 'Eve', score: 890 },
];

const topThree = players
  .toSorted((a, b) => b.score - a.score)
  .slice(0, 3)
  .map((p, i) => `${i + 1}. ${p.name} (${p.score})`);
console.log(topThree);
// ['1. Diana (950)', '2. Bob (920)', '3. Eve (890)']

12. 性能对比(Big-O)

理解时间复杂度有助于为大数据集选择正确的方法。以下是每个主要数组方法的参考表。

// Performance reference table (n = array length)
//
// ┌──────────────────────┬──────────────┬──────────────────────────────────────┐
// │ Method               │ Time         │ Notes                                │
// ├──────────────────────┼──────────────┼──────────────────────────────────────┤
// │ push()               │ O(1) amort.  │ Occasional resize → O(n)             │
// │ pop()                │ O(1)         │ Fastest removal                      │
// │ unshift()            │ O(n)         │ Must shift all elements right        │
// │ shift()              │ O(n)         │ Must shift all elements left         │
// │ splice(i, k)         │ O(n)         │ Must shift elements after index i    │
// │ concat()             │ O(n + m)     │ n = arr1.length, m = arr2.length     │
// │ slice()              │ O(k)         │ k = number of elements copied        │
// │ indexOf() / includes │ O(n)         │ Linear scan, worst case full array   │
// │ find() / findIndex() │ O(n)         │ Stops at first match (best O(1))     │
// │ some() / every()     │ O(n)         │ Short-circuits on match/failure      │
// │ map()                │ O(n)         │ Visits every element                 │
// │ filter()             │ O(n)         │ Visits every element                 │
// │ reduce()             │ O(n)         │ Visits every element                 │
// │ forEach()            │ O(n)         │ Visits every element                 │
// │ flat(depth)          │ O(n)         │ n = total elements after flattening  │
// │ flatMap()            │ O(n)         │ map + flat(1) in one pass            │
// │ sort()               │ O(n log n)   │ TimSort in V8 (stable)               │
// │ reverse()            │ O(n)         │ In-place swap                        │
// │ fill()               │ O(n)         │ Fills every position                 │
// │ Array.from()         │ O(n)         │ Iterates source + optional map       │
// │ [...spread]          │ O(n)         │ Shallow copy                         │
// │ structuredClone()    │ O(n)         │ Deep copy, handles circular refs     │
// │ toSorted()           │ O(n log n)   │ Copy + sort                          │
// │ toReversed()         │ O(n)         │ Copy + reverse                       │
// │ toSpliced()          │ O(n)         │ Copy + splice                        │
// │ with()               │ O(n)         │ Copy + single index change           │
// └──────────────────────┴──────────────┴──────────────────────────────────────┘
//
// Tips:
// • For frequent add/remove at both ends → use a Deque or linked list
// • For frequent lookups by value → use a Set (O(1) has/add/delete)
// • For frequent lookups by key → use a Map (O(1) get/set/delete)
// • Avoid nested find/filter inside loops → O(n²), use Map for O(n)
// Benchmark: Set vs indexOf for duplicate removal
function benchmarkDedup() {
  const arr = Array.from({ length: 100000 }, () =>
    Math.floor(Math.random() * 10000)
  );

  // Method 1: filter + indexOf — O(n²)
  console.time('filter+indexOf');
  const unique1 = arr.filter((v, i, a) => a.indexOf(v) === i);
  console.timeEnd('filter+indexOf');  // ~200-500ms

  // Method 2: Set — O(n)
  console.time('Set');
  const unique2 = [...new Set(arr)];
  console.timeEnd('Set');  // ~5-10ms

  console.log(unique1.length, unique2.length); // same result
}

// Benchmark: push vs unshift on large arrays
function benchmarkPushVsUnshift() {
  const n = 100000;

  console.time('push');
  const arr1 = [];
  for (let i = 0; i < n; i++) arr1.push(i);
  console.timeEnd('push');  // ~5ms

  console.time('unshift');
  const arr2 = [];
  for (let i = 0; i < n; i++) arr2.unshift(i);
  console.timeEnd('unshift');  // ~1000ms+ (O(n²) total!)
}

13. 常见问题

JavaScript 中 map() 和 forEach() 有什么区别?

map() 返回一个新数组,其中包含对每个元素调用函数的结果;而 forEach() 返回 undefined,仅用于副作用操作。当你需要转换后的数组时使用 map();当你只需要对每个元素执行代码(如日志记录、DOM 更新)时使用 forEach()。map() 可以链式调用,forEach() 不行。

哪些 JavaScript 数组方法会修改原数组?

变异方法有:push()、pop()、shift()、unshift()、splice()、sort()、reverse()、fill() 和 copyWithin()。ES2023 引入了非变异替代方案:toSorted()、toReversed()、toSpliced() 和 with()。map()、filter()、reduce()、slice()、concat()、flat() 和 flatMap() 等方法始终返回新数组,不会修改原数组。

如何去除 JavaScript 数组中的重复元素?

最简洁的方式是 [...new Set(array)] 或 Array.from(new Set(array))。对于对象数组,使用 filter 配合 Set 跟踪唯一键:array.filter((item, i, arr) => arr.findIndex(x => x.id === item.id) === i)。对于大数组,Set 方法是 O(n),而 findIndex 方法是 O(n^2)。

JavaScript 中 find() 和 filter() 有什么区别?

find() 返回第一个匹配条件的元素并停止搜索(短路),如果没有匹配则返回 undefined。filter() 返回所有匹配元素的新数组,如果没有匹配则返回空数组。当你需要单个结果时使用 find();当你需要所有匹配项时使用 filter()。

JavaScript 中 reduce() 是如何工作的?

reduce() 接收一个回调函数和一个可选的初始值。回调接收四个参数:accumulator(累加器)、currentValue(当前值)、currentIndex(当前索引)和数组本身。它遍历每个元素,将每次回调的返回值作为下一次迭代的累加器。常见用途包括求和、展平数组、分组对象以及从数组构建对象。

收藏此速查表以便快速参考。要处理 JavaScript 和 JSON 数据,请试试下面的工具。

试试 JS/HTML 格式化工具 →

试试 JSON 格式化工具 →

𝕏 Twitterin LinkedIn
这篇文章有帮助吗?

保持更新

获取每周开发技巧和新工具通知。

无垃圾邮件,随时退订。

试试这些相关工具

{ }JSON FormatterJSJS/HTML Formatter.*Regex Tester

相关文章

JavaScript 字符串正则替换:replaceAll、捕获组与示例

掌握 JavaScript 中使用正则表达式的字符串替换。学习 replace 与 replaceAll、全局标志、捕获组、前瞻断言和实际示例。

JavaScript map()、filter()、reduce() 示例

掌握 JavaScript 函数式编程:map、filter 和 reduce。学习链式调用、实际数据转换、性能技巧和常见陷阱。