modern-javascript

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Modern JavaScript (ES6-ES2025)

现代JavaScript(ES6-ES2025)

Write clean, performant, maintainable JavaScript using modern language features. This skill covers ES6 through ES2025, emphasizing immutability, functional patterns, and expressive syntax.
利用现代语言特性编写简洁、高性能、可维护的JavaScript代码。本技能涵盖ES6至ES2025,强调不可变性、函数式模式和富有表现力的语法。

Quick Decision Trees

快速决策树

"Which array method should I use?"

"我应该使用哪种数组方法?"

What do I need?
├─ Transform each element           → .map()
├─ Keep some elements               → .filter()
├─ Find one element                 → .find() / .findLast()
├─ Check if condition met           → .some() / .every()
├─ Reduce to single value           → .reduce()
├─ Get last element                 → .at(-1)
├─ Sort without mutating            → .toSorted()
├─ Reverse without mutating         → .toReversed()
├─ Group by property                → Object.groupBy()
└─ Flatten nested arrays            → .flat() / .flatMap()
我需要做什么?
├─ 转换每个元素           → .map()
├─ 筛选部分元素           → .filter()
├─ 查找单个元素           → .find() / .findLast()
├─ 检查是否满足条件       → .some() / .every()
├─ 归约为单个值           → .reduce()
├─ 获取最后一个元素       → .at(-1)
├─ 排序且不修改原数组     → .toSorted()
├─ 反转且不修改原数组     → .toReversed()
├─ 按属性分组             → Object.groupBy()
└─ 扁平化嵌套数组         → .flat() / .flatMap()

"How do I handle nullish values?"

"如何处理空值?"

Nullish handling?
├─ Safe property access              → obj?.prop / obj?.[key]
├─ Safe method call                  → obj?.method?.()
├─ Default for null/undefined only   → value ?? 'default'
├─ Default for any falsy             → value || 'default'
├─ Assign if null/undefined          → obj.prop ??= 'default'
└─ Check property exists             → Object.hasOwn(obj, 'key')
空值处理?
├─ 安全访问属性            → obj?.prop / obj?.[key]
├─ 安全调用方法            → obj?.method?.()
├─ 仅为null/undefined设置默认值 → value ?? 'default'
├─ 为任何假值设置默认值    → value || 'default'
├─ 仅当为null/undefined时赋值 → obj.prop ??= 'default'
└─ 检查属性是否存在        → Object.hasOwn(obj, 'key')

"Should I mutate or copy?"

"应该修改原对象还是创建副本?"

Always prefer non-mutating methods:
├─ Sort array      → .toSorted()    (not .sort())
├─ Reverse array   → .toReversed()  (not .reverse())
├─ Splice array    → .toSpliced()   (not .splice())
├─ Update element  → .with(i, val)  (not arr[i] = val)
├─ Add to array    → [...arr, item] (not .push())
└─ Merge objects   → {...obj, key}  (not Object.assign())
优先选择非修改式方法:
├─ 数组排序      → .toSorted()    (而非.sort())
├─ 数组反转      → .toReversed()  (而非.reverse())
├─ 数组删除元素  → .toSpliced()   (而非.splice())
├─ 更新数组元素  → .with(i, val)  (而非arr[i] = val)
├─ 向数组添加元素→ [...arr, item] (而非.push())
└─ 合并对象      → {...obj, key}  (而非Object.assign())

ES Version Quick Reference

ES版本速查表

VersionYearKey Features
ES62015let/const, arrow functions, classes, destructuring, spread, Promises, modules, Symbol, Map/Set, Proxy, generators
ES20162016Array.includes(), exponentiation operator **
ES20172017async/await, Object.values/entries, padStart/padEnd, trailing commas, SharedArrayBuffer, Atomics
ES20182018Rest/spread for objects, for await...of, Promise.finally(), RegExp named groups, lookbehind, dotAll flag
ES20192019.flat(), .flatMap(), Object.fromEntries(), trimStart/End(), optional catch binding, stable Array.sort()
ES20202020Optional chaining ?., nullish coalescing ??, BigInt, Promise.allSettled(), globalThis, dynamic import()
ES20212021String.replaceAll(), Promise.any(), logical assignment ??= and or=, numeric separators 1_000_000
ES20222022.at(), Object.hasOwn(), top-level await, private class fields #field, static blocks, Error.cause
ES20232023.toSorted(), .toReversed(), .toSpliced(), .with(), .findLast(), .findLastIndex(), hashbang grammar
ES20242024Object.groupBy(), Map.groupBy(), Promise.withResolvers(), RegExp v flag, resizable ArrayBuffer
ES20252025Iterator helpers (.map, .filter, .take), Set methods (.union, .intersection), RegExp.escape(), using/await using
版本年份关键特性
ES62015let/const、箭头函数、类、解构、展开、Promises、模块、Symbol、Map/Set、Proxy、生成器
ES20162016Array.includes()、指数运算符 **
ES20172017async/await、Object.values/entries、padStart/padEnd、尾逗号、SharedArrayBuffer、Atomics
ES20182018对象的剩余/展开、for await...of、Promise.finally()、正则表达式命名组、后行断言、dotAll标志
ES20192019.flat()、.flatMap()、Object.fromEntries()、trimStart/End()、可选catch绑定、稳定的Array.sort()
ES20202020可选链 ?.、空值合并 ??、BigInt、Promise.allSettled()、globalThis、动态import()
ES20212021String.replaceAll()、Promise.any()、逻辑赋值 ??= 和 or=、数字分隔符 1_000_000
ES20222022.at()、Object.hasOwn()、顶层await、私有类字段 #field、静态块、Error.cause
ES20232023.toSorted()、.toReversed()、.toSpliced()、.with()、.findLast()、.findLastIndex()、hashbang语法
ES20242024Object.groupBy()、Map.groupBy()、Promise.withResolvers()、正则表达式v标志、可调整大小的ArrayBuffer
ES20252025迭代器辅助方法(.map、.filter、.take)、Set方法(.union、.intersection)、RegExp.escape()、using/await using

Modernization Patterns

现代化模式

Array Access

数组访问

javascript
// ❌ Legacy
const last = arr[arr.length - 1];
const secondLast = arr[arr.length - 2];

// ✅ Modern (ES2022)
const last = arr.at(-1);
const secondLast = arr.at(-2);
javascript
// ❌ 遗留写法
const last = arr[arr.length - 1];
const secondLast = arr[arr.length - 2];

// ✅ 现代写法(ES2022)
const last = arr.at(-1);
const secondLast = arr.at(-2);

Non-Mutating Array Operations

非修改式数组操作

javascript
// ❌ Mutates original array
const sorted = arr.sort((a, b) => a - b);
const reversed = arr.reverse();

// ✅ Returns new array (ES2023)
const sorted = arr.toSorted((a, b) => a - b);
const reversed = arr.toReversed();
const updated = arr.with(2, 'new value');
const removed = arr.toSpliced(1, 1);
javascript
// ❌ 修改原数组
const sorted = arr.sort((a, b) => a - b);
const reversed = arr.reverse();

// ✅ 返回新数组(ES2023)
const sorted = arr.toSorted((a, b) => a - b);
const reversed = arr.toReversed();
const updated = arr.with(2, 'new value');
const removed = arr.toSpliced(1, 1);

String Replacement

字符串替换

javascript
// ❌ Legacy with regex
const result = str.replace(/foo/g, 'bar');

// ✅ Modern (ES2021)
const result = str.replaceAll('foo', 'bar');
javascript
// ❌ 使用正则表达式的遗留写法
const result = str.replace(/foo/g, 'bar');

// ✅ 现代写法(ES2021)
const result = str.replaceAll('foo', 'bar');

Grouping Data

数据分组

javascript
// ❌ Manual grouping
const grouped = items.reduce((acc, item) => {
  const key = item.category;
  acc[key] = acc[key] || [];
  acc[key].push(item);
  return acc;
}, {});

// ✅ Modern (ES2024)
const grouped = Object.groupBy(items, item => item.category);
javascript
// ❌ 手动分组
const grouped = items.reduce((acc, item) => {
  const key = item.category;
  acc[key] = acc[key] || [];
  acc[key].push(item);
  return acc;
}, {});

// ✅ 现代写法(ES2024)
const grouped = Object.groupBy(items, item => item.category);

Nullish Handling

空值处理

javascript
// ❌ Falsy check (0, '', false are valid values)
const value = input || 'default';
const name = user && user.profile && user.profile.name;

// ✅ Nullish check (only null/undefined)
const value = input ?? 'default';
const name = user?.profile?.name;
javascript
// ❌ 假值检查(0、''、false会被误判)
const value = input || 'default';
const name = user && user.profile && user.profile.name;

// ✅ 空值检查(仅针对null/undefined)
const value = input ?? 'default';
const name = user?.profile?.name;

Property Existence

属性存在性检查

javascript
// ❌ Can be fooled by prototype or overwritten hasOwnProperty
if (obj.hasOwnProperty('key')) { }

// ✅ Modern (ES2022)
if (Object.hasOwn(obj, 'key')) { }
javascript
// ❌ 可能被原型覆盖或hasOwnProperty被重写
if (obj.hasOwnProperty('key')) { }

// ✅ 现代写法(ES2022)
if (Object.hasOwn(obj, 'key')) { }

Logical Assignment

逻辑赋值

javascript
// ❌ Verbose assignment
if (obj.prop === null || obj.prop === undefined) {
  obj.prop = 'default';
}

// ✅ Modern (ES2021)
obj.prop ??= 'default';  // Assign if null/undefined
obj.count ||= 0;         // Assign if falsy
obj.enabled &&= check(); // Assign if truthy
javascript
// ❌ 冗长的赋值写法
if (obj.prop === null || obj.prop === undefined) {
  obj.prop = 'default';
}

// ✅ 现代写法(ES2021)
obj.prop ??= 'default';  // 仅当为null/undefined时赋值
obj.count ||= 0;         // 为假值时赋值
obj.enabled &&= check(); // 为真值时赋值

Async Patterns

异步模式

Promise Combinators

Promise组合器

javascript
// Wait for all, fail if any fails
const [users, posts] = await Promise.all([fetchUsers(), fetchPosts()]);

// Wait for all, get status of each
const results = await Promise.allSettled([fetchA(), fetchB()]);
results.forEach(r => {
  if (r.status === 'fulfilled') console.log(r.value);
  else console.error(r.reason);
});

// First to succeed
const fastest = await Promise.any([fetchFromCDN1(), fetchFromCDN2()]);

// First to settle
const winner = await Promise.race([fetchData(), timeout(5000)]);
javascript
// 等待所有Promise完成,任一失败则整体失败
const [users, posts] = await Promise.all([fetchUsers(), fetchPosts()]);

// 等待所有Promise完成,获取每个的状态
const results = await Promise.allSettled([fetchA(), fetchB()]);
results.forEach(r => {
  if (r.status === 'fulfilled') console.log(r.value);
  else console.error(r.reason);
});

// 等待第一个成功的Promise
const fastest = await Promise.any([fetchFromCDN1(), fetchFromCDN2()]);

// 等待第一个完成的Promise(无论成功或失败)
const winner = await Promise.race([fetchData(), timeout(5000)]);

Promise.withResolvers (ES2024)

Promise.withResolvers(ES2024)

javascript
// ❌ Legacy pattern
let resolve, reject;
const promise = new Promise((res, rej) => {
  resolve = res;
  reject = rej;
});

// ✅ Modern (ES2024)
const { promise, resolve, reject } = Promise.withResolvers();
javascript
// ❌ 遗留模式
let resolve, reject;
const promise = new Promise((res, rej) => {
  resolve = res;
  reject = rej;
});

// ✅ 现代写法(ES2024)
const { promise, resolve, reject } = Promise.withResolvers();

Top-Level Await (ES2022)

顶层Await(ES2022)

javascript
// In ES modules, await at top level
const config = await fetch('/config.json').then(r => r.json());
const db = await connectDatabase(config);

export { db };
javascript
// 在ES模块中,可在顶层使用await
const config = await fetch('/config.json').then(r => r.json());
const db = await connectDatabase(config);

export { db };

Functional Patterns

函数式模式

Immutable Object Updates

不可变对象更新

javascript
// Add/update property
const updated = { ...user, age: 31 };

// Remove property
const { password, ...userWithoutPassword } = user;

// Nested update
const updated = {
  ...state,
  user: { ...state.user, name: 'New Name' }
};
javascript
// 添加/更新属性
const updated = { ...user, age: 31 };

// 删除属性
const { password, ...userWithoutPassword } = user;

// 嵌套更新
const updated = {
  ...state,
  user: { ...state.user, name: 'New Name' }
};

Array Transformations

数组转换

javascript
// Chain transformations (ES2023)
const result = users
  .filter(u => u.active)
  .map(u => u.name)
  .toSorted();

// Using flatMap for filter+map (single pass)
const activeNames = users.flatMap(u => u.active ? [u.name] : []);

// ES2024: Group then process
const byStatus = Object.groupBy(users, u => u.active ? 'active' : 'inactive');
const activeNames = byStatus.active?.map(u => u.name) ?? [];
javascript
// 链式转换(ES2023)
const result = users
  .filter(u => u.active)
  .map(u => u.name)
  .toSorted();

// 使用flatMap同时完成过滤和映射(单次遍历)
const activeNames = users.flatMap(u => u.active ? [u.name] : []);

// ES2024:先分组再处理
const byStatus = Object.groupBy(users, u => u.active ? 'active' : 'inactive');
const activeNames = byStatus.active?.map(u => u.name) ?? [];

Composition

函数组合

javascript
const pipe = (...fns) => x => fns.reduce((v, f) => f(v), x);
const compose = (...fns) => x => fns.reduceRight((v, f) => f(v), x);

const processUser = pipe(
  user => ({ ...user, name: user.name.trim() }),
  user => ({ ...user, email: user.email.toLowerCase() }),
  user => ({ ...user, createdAt: new Date() })
);
javascript
const pipe = (...fns) => x => fns.reduce((v, f) => f(v), x);
const compose = (...fns) => x => fns.reduceRight((v, f) => f(v), x);

const processUser = pipe(
  user => ({ ...user, name: user.name.trim() }),
  user => ({ ...user, email: user.email.toLowerCase() }),
  user => ({ ...user, createdAt: new Date() })
);

Destructuring Patterns

解构模式

Object Destructuring

对象解构

javascript
// Basic with rename and default
const { name: userName, age = 18 } = user;

// Nested
const { address: { city, country } } = user;

// Rest
const { id, ...userData } = user;
javascript
// 基础用法,支持重命名和默认值
const { name: userName, age = 18 } = user;

// 嵌套解构
const { address: { city, country } } = user;

// 剩余解构
const { id, ...userData } = user;

Array Destructuring

数组解构

javascript
// Skip elements
const [first, , third] = array;

// Rest
const [head, ...tail] = array;

// Swap variables
[a, b] = [b, a];

// Function returns
const [x, y] = getCoordinates();
javascript
// 跳过元素
const [first, , third] = array;

// 剩余解构
const [head, ...tail] = array;

// 变量交换
[a, b] = [b, a];

// 函数返回值解构
const [x, y] = getCoordinates();

Anti-Patterns

反模式

Anti-PatternProblemModern Solution
arr[arr.length-1]
Verbose, error-prone
arr.at(-1)
.sort()
on original
Mutates array
.toSorted()
.replace(/g/)
for all
Regex overhead
.replaceAll()
obj.hasOwnProperty()
Can be overwritten
Object.hasOwn()
value || default
0, '', false treated as falsy
value ?? default
obj && obj.prop && obj.prop.method()
Verbose null checks
obj?.prop?.method?.()
for (let i = 0; ...)
Index bugs, verbose
.map()
,
.filter()
,
for...of
new Promise((res, rej) => ...)
Boilerplate
Promise.withResolvers()
Manual array groupingVerbose, error-prone
Object.groupBy()
反模式问题现代解决方案
arr[arr.length-1]
冗长且易出错
arr.at(-1)
.sort()
修改原数组
修改原数组
.toSorted()
.replace(/g/)
全局替换
正则表达式开销大
.replaceAll()
obj.hasOwnProperty()
可能被重写
Object.hasOwn()
`valuedefault`
obj && obj.prop && obj.prop.method()
空值检查冗长
obj?.prop?.method?.()
for (let i = 0; ...)
循环
索引易出错且冗长
.map()
.filter()
for...of
new Promise((res, rej) => ...)
样板代码过多
Promise.withResolvers()
手动数组分组冗长且易出错
Object.groupBy()

Best Practices

最佳实践

  1. Use
    const
    by default
    — Only use
    let
    when reassignment is needed
  2. Prefer arrow functions — Especially for callbacks and short functions
  3. Use template literals — Instead of string concatenation
  4. Destructure early — Extract what you need at function start
  5. Avoid mutations — Use
    .toSorted()
    ,
    .toReversed()
    , spread operator
  6. Use optional chaining — Prevent "Cannot read property of undefined"
  7. Use nullish coalescing
    ??
    for defaults, not
    ||
    (unless intentional)
  8. Prefer array methods
    .map()
    ,
    .filter()
    ,
    .find()
    over loops
  9. Use
    async/await
    — Instead of
    .then()
    chains
  10. Handle errors properly
    try/catch
    with async/await
  1. 默认使用
    const
    —— 仅在需要重新赋值时使用
    let
  2. 优先使用箭头函数 —— 尤其适用于回调函数和短函数
  3. 使用模板字面量 —— 替代字符串拼接
  4. 尽早解构 —— 在函数开头提取所需内容
  5. 避免修改原对象 —— 使用
    .toSorted()
    .toReversed()
    、展开运算符
  6. 使用可选链 —— 避免出现“Cannot read property of undefined”错误
  7. 使用空值合并运算符 —— 用
    ??
    设置默认值,而非
    ||
    (除非故意为之)
  8. 优先使用数组方法 —— 用
    .map()
    .filter()
    .find()
    替代循环
  9. 使用
    async/await
    —— 替代
    .then()
    链式调用
  10. 正确处理错误 —— 结合
    async/await
    使用
    try/catch

Reference Documentation

参考文档

ES Version References

ES版本参考

FilePurpose
references/ES2016-ES2017.mdincludes, async/await, Object.values/entries, string padding
references/ES2018-ES2019.mdrest/spread objects, flat/flatMap, RegExp named groups
references/ES2022-ES2023.md.at(), .toSorted(), .toReversed(), .findLast(), class features
references/ES2024.mdObject.groupBy, Promise.withResolvers, RegExp v flag
references/ES2025.mdSet methods, iterator helpers, using/await using
references/UPCOMING.mdTemporal API, Decorators, Decorator Metadata
文件用途
references/ES2016-ES2017.mdincludes、async/await、Object.values/entries、字符串填充
references/ES2018-ES2019.md对象的剩余/展开、flat/flatMap、正则表达式命名组
references/ES2022-ES2023.md.at()、.toSorted()、.toReversed()、.findLast()、类特性
references/ES2024.mdObject.groupBy、Promise.withResolvers、正则表达式v标志
references/ES2025.mdSet方法、迭代器辅助方法、using/await using
references/UPCOMING.mdTemporal API、装饰器、装饰器元数据

Pattern References

模式参考

FilePurpose
references/PROMISES.mdPromise fundamentals, async/await, combinators
references/CONCURRENCY.mdParallel, batched, pool patterns, retry, cancellation
references/IMMUTABILITY.mdImmutable data patterns, pure functions
references/COMPOSITION.mdHigher-order functions, memoization, monads
references/CHEATSHEET.mdQuick syntax reference
文件用途
references/PROMISES.mdPromise基础、async/await、组合器
references/CONCURRENCY.md并行、批处理、池化模式、重试、取消
references/IMMUTABILITY.md不可变数据模式、纯函数
references/COMPOSITION.md高阶函数、记忆化、单子
references/CHEATSHEET.md快速语法参考

Resources

资源

Specifications

规范

Documentation

文档

Compatibility

兼容性