什么?JavaScript 也搞了个类似 Rust 的模式匹配语法

本文来自公众号 猩猩程序员 欢迎关注

Rust 的 match 是其语言的基石之一,以其强大的表现力和编译时安全检查而闻名。JS 提案几乎是将其核心思想"翻译"到了 JavaScript 的动态世界中。

我们来深入解读一下 TC39 关于 JavaScript 模式匹配(Pattern Matching)提案的核心内容。

请注意,这个功能目前仍处于 Stage 1 提案阶段 ,意味着它正在早期探索中,语法和行为将来可能会有很大变化,现在还不能在任何浏览器或 Node.js 环境中直接使用


JavaScript 模式匹配教程 (基于 TC39 提案)

想象一下,如果 if/elseswitch 语句能变得更强大、更具表现力,能够直接解构并检查对象的"形状",那会怎么样?这就是模式匹配想要解决的问题。它旨在提供一种更声明式、更强大的方式来根据数据的结构执行不同的代码逻辑。

1. 核心语法:match 表达式

模式匹配的核心是一个新的表达式:match。记住,它是一个表达式 ,不是一个语句,这意味着它会返回一个值

基本结构如下:

javascript 复制代码
// 这是一个尚未实现的语法
let result = match (someValue) {
  when (pattern1) { /* ... do something ... */ }
  when (pattern2 if someCondition) { /* ... do something else ... */ }
  // ... more when clauses ...
  else { /* ... default case ... */ }
}
  • match (someValue):将 someValue 作为输入进行匹配。
  • when (pattern):定义一个模式。someValue 会依次与每个 pattern 进行比较。
  • { ... }:一旦找到第一个匹配的 pattern,对应的代码块就会执行,并且 match 表达式会返回这个代码块的结果。
  • if someCondition:这是可选的"守卫子句 (Guard Clause)",允许你在模式匹配的基础上增加额外的判断条件。
  • else { ... }:如果没有任何 when 子句匹配成功,则执行 else 块。这类似于 switch 中的 default

2. 强大的武器:模式 (Patterns)

这部分是模式匹配最激动人心的地方,也是提案的核心。一个"模式"可以是一个简单的值,也可以是一个复杂的结构。

a. 字面量模式 (Literal Pattern)

这是最简单的模式,用于匹配精确的值,就像 switchcase 一样。

javascript 复制代码
function getMimeType(fileExtension) {
  return match (fileExtension) {
    when ('html') { 'text/html' }
    when ('css') { 'text/css' }
    when ('js') { 'application/javascript' }
    else { 'application/octet-stream' }
  };
}

console.log(getMimeType('js')); // 输出: 'application/javascript'
b. 标识符模式 (Identifier Pattern) & 绑定

你可以使用一个变量名作为模式,这会匹配任何值,并将该值绑定到这个变量名上 ,以便在 when 的代码块和守卫子句中使用。

javascript 复制代码
function handleResponse(response) {
  return match (response) {
    // 匹配任何值,并将其绑定到 status 变量
    when ({ status } if status >= 200 && status < 300) {
      return `Success with status: ${status}`;
    }
    when ({ status }) { // 再次绑定
      return `Failure with status: ${status}`;
    }
  }
}
c. 通配符模式 (Wildcard Pattern _)

如果你想匹配任何东西,但又不关心 它的具体值(即不需要绑定它),可以使用下划线 _ 作为通配符。

else 块的内部,else 实际上就是 when (_) 的语法糖。

javascript 复制代码
function isImportant(message) {
  return match (message) {
    when ({ type: 'error' }) { true }
    when ({ type: 'warning' }) { true }
    // 匹配任何其他情况,但不关心其内容
    when (_) { false } 
  };
}
d. 对象模式 (Object Pattern)

这是模式匹配真正强大的地方。你可以匹配一个对象的"形状",并同时解构它。

javascript 复制代码
function handleAction(action) {
  return match (action) {
    // 匹配一个有 type: 'FETCH_SUCCESS' 和 data 属性的对象
    // 同时将 data 属性的值绑定到 payload 变量
    when ({ type: 'FETCH_SUCCESS', data: payload }) {
      console.log('Data received:', payload);
      return 'Displaying data.';
    }
    // 匹配一个有 type: 'FETCH_ERROR' 和 error 属性的对象
    // 同时将 error 属性的值绑定到 error 变量
    when ({ type: 'FETCH_ERROR', error }) { // { error } 是 { error: error } 的简写
      console.error('Error:', error.message);
      return 'Displaying error message.';
    }
    when ({ type: 'FETCH_PENDING' }) {
      return 'Loading...';
    }
  }
}

handleAction({ type: 'FETCH_SUCCESS', data: { user: 'Alice' } });
// 输出: Data received: { user: 'Alice' }
e. 数组模式 (Array Pattern)

与对象模式类似,你可以匹配数组的结构,包括固定元素、剩余元素等。

javascript 复制代码
function executeCommand(command) {
  return match (command) {
    // 匹配以 'add' 开头,且后面跟着一个元素的数组
    when (['add', item]) {
      console.log(`Adding ${item}...`);
    }
    // 匹配以 'delete' 开头,且后面跟着一个数字 ID 的数组
    when (['delete', id] if typeof id === 'number') {
      console.log(`Deleting item #${id}...`);
    }
    // 匹配一个空数组
    when ([]) {
      console.log('No command given.');
    }
    // 匹配任何其他数组,并将所有元素绑定到 `args`
    when ([...args]) {
      console.log(`Unknown command: ${args.join(' ')}`);
    }
  }
}

executeCommand(['delete', 123]); // 输出: Deleting item #123...
executeCommand(['move', 'file.txt']); // 输出: Unknown command: move file.txt

3. 点睛之笔:守卫子句 (Guard Clause if)

有时,仅匹配结构是不够的,你还需要检查值的属性。if 守卫子句让这一切成为可能。

javascript 复制代码
function getDiscount(user) {
  return match (user) {
    // 匹配一个 VIP 用户,并且他的消费超过 1000
    when ({ type: 'VIP', spending } if spending > 1000) {
      return 0.2; // 20% 折扣
    }
    // 匹配任何 VIP 用户
    when ({ type: 'VIP' }) {
      return 0.1; // 10% 折扣
    }
    // 匹配一个普通用户,并且是新注册的
    when ({ type: 'Normal', isNew: true }) {
      return 0.05; // 5% 折扣
    }
    else {
      return 0;
    }
  }
}

粽结

JavaScript 的模式匹配提案为我们描绘了一个美好的未来:

  1. 声明式:代码直接描述"你想要什么样的数据",而不是"你如何去检查数据"。
  2. 更安全 :它避免了 switch 语句忘记写 break 导致的"意外贯穿"问题。
  3. 解构与匹配合一:在检查数据结构的同时完成解构赋值,代码更简洁。
  4. 处理复杂嵌套数据:对于复杂的 JSON 对象或 API 响应,模式匹配可以极大地简化处理逻辑。

虽然我们还需要等待一段时间才能在项目中使用它,但了解其设计思想有助于我们写出更清晰、更易于维护的条件逻辑。

学过Rust的人应该对这些语法比较熟悉,可以说,JavaScript 的模式匹配提案是 Rust match 表达式在动态语言领域的一次"精神传承"。它借鉴了 Rust 成熟的、富有表现力的语法,旨在解决传统 if/else 和 switch 在处理复杂数据结构时的笨拙和繁琐。

本文来自公众号 猩猩程序员 欢迎关注

相关推荐
LLLLYYYRRRRRTT2 分钟前
MariaDB 数据库管理与web服务器
前端·数据库·mariadb
胡gh3 分钟前
什么是瀑布流?用大白话给你讲明白!
前端·javascript·面试
universe_019 分钟前
day22|学习前端ts语言
前端·笔记
teeeeeeemo13 分钟前
一些js数组去重的实现算法
开发语言·前端·javascript·笔记·算法
Zz_waiting.14 分钟前
Javaweb - 14.1 - 前端工程化
前端·es6
掘金安东尼16 分钟前
前端周刊第426期(2025年8月4日–8月10日)
前端·javascript·面试
Abadbeginning16 分钟前
FastSoyAdmin导出excel报错‘latin-1‘ codec can‘t encode characters in position 41-54
前端·javascript·后端
ZXT18 分钟前
WebAssembly
前端
卢叁18 分钟前
Flutter开发环境安装指南
前端·flutter
curdcv_po36 分钟前
Three.js,闲谈3D——智慧XX
前端