JS 进阶:ES6+ 核心语法与异步编程

在学习完 JavaScript 的基础语法(如变量、条件判断、DOM 操作)后,我们往往会直接进入前端框架(如 Vue、React)或网络请求(如 Fetch)的学习。

但在这个过程中,很多初学者会遇到一个巨大的语法断层。现代前端代码中充斥着类似 const { data } = res...obj() => {}async/await 这样的写法,这些其实都是 ES6(ECMAScript 2015)及以后版本 引入的新特性。

这篇文章旨在帮你夯实这层“隐形地基”,彻底扫清阅读现代 JS 源码时的语法障碍。

1. 箭头函数:更简洁的函数写法

传统 JavaScript 中定义函数使用 function 关键字:

function add(a, b) {
  return a + b;
}

ES6 引入了箭头函数 (=>),让代码更加紧凑:

// 基础写法
const add = (a, b) => {
  return a + b;
};

// 如果函数体只有一行 return 语句,可以省略大括号和 return 关键字
const multiply = (a, b) => a * b;

// 如果只有一个参数,连小括号都可以省略
const square = x => x * x;

💡 注意: 箭头函数除了写法简洁,还有一个非常重要的特性:它没有自己的 this,它的 this 永远指向它定义时所在的上下文环境。这在很多回调函数中能解决 this 指向丢失的问题。

2. 解构赋值:优雅地提取数据

解构赋值允许我们按照一定的模式,从数组或对象中提取值,直接赋值给变量。这是在 Vue 组件和处理接口数据时最常用的语法。

2.1 对象的解构

以前我们从对象中取值需要这样写:

const user = { name: 'Alice', age: 20, city: 'Beijing' };
const name = user.name;
const age = user.age;

现在可以这样写(变量名必须和对象的属性名一致):

const user = { name: 'Alice', age: 20, city: 'Beijing' };

// 一行代码提取 name 和 age
const { name, age } = user;
console.log(name); // "Alice"

2.2 数组的解构

数组解构是按顺序提取的:

const numbers = [10, 20, 30];
// 按位置提取数组中的值
const [first, second] = numbers;

console.log(first); // 10
console.log(second); // 20

3. 展开运算符(Spread Operator)

展开运算符是三个点 ...。它可以在函数调用/数组构造时,将数组表达式或者 string 在语法层面展开;还可以在构造字面量对象时,将对象表达式按 key-value 的方式展开。

3.1 数组的展开与合并

const arr1 = [1, 2];
const arr2 = [3, 4];

// 合并数组,以前用 arr1.concat(arr2)
const combined = [...arr1, ...arr2]; // [1, 2, 3, 4]

// 复制数组(浅拷贝)
const copy = [...arr1];

3.2 对象的展开与合并

在 Vuex 或 Pinia 的状态管理,或者传递 API 参数时非常常见:

const user = { name: 'Bob', age: 25 };

// 复制对象,并添加/覆盖新属性
const updatedUser = { 
  ...user, 
  age: 26, 
  job: 'Developer' 
};

console.log(updatedUser); 
// { name: 'Bob', age: 26, job: 'Developer' }

4. 异步编程:彻底理解 Promise

JavaScript 是单线程执行的。如果某段代码需要等待很长时间(例如网络请求、读取文件),它就会阻塞后续代码的运行,导致页面卡死。为了解决这个问题,JS 采用了异步编程机制。

过去处理异步,主要靠回调函数(Callback),但这容易导致层层嵌套的“回调地狱(Callback Hell)”。于是,ES6 引入了 Promise

4.1 什么是 Promise?

Promise 就像是一张“承诺凭证”。想象你去奶茶店点单,店员给你一个小票(Promise 对象)。这时候奶茶还没做好(处于 pending 状态),你可以去干别的事。

  • 当奶茶做好了,店员叫你的号,这就叫 兑现(fulfilled/resolved)
  • 如果机器坏了做不了,店员告诉你退款,这就叫 拒绝(rejected)

4.2 基本用法:.then().catch()

// 假设 fetchData 返回一个 Promise
fetchData()
  .then(data => {
    // 当 Promise 成功兑现时,执行这里
    console.log("获取成功", data);
  })
  .catch(error => {
    // 当 Promise 被拒绝时,执行这里
    console.log("出错了", error);
  })
  .finally(() => {
    // 无论成功还是失败,最后都会执行这里(比如用来隐藏 loading 动画)
    console.log("请求结束");
  });

5. 异步终极方案:async / await

虽然 Promise 解决了回调地狱,但用一堆 .then() 链式调用,代码看着还是不够像“正常”的同步代码。

于是 ES8 (ECMAScript 2017) 推出了 asyncawait,它们是基于 Promise 的语法糖,能让我们用写同步代码的方式来写异步逻辑

5.1 核心规则

  1. async 用于声明一个异步函数,该函数会隐式地返回一个 Promise。
  2. await 只能在 async 函数内部使用。它会暂停代码在这个位置的执行,直到后面的 Promise 完成并返回结果,然后再往下走。

5.2 代码对比

.then() 写法(Fetch 请求):

function getUser() {
  // fetch 本身返回一个 Promise
  fetch('https://api.example.com/user')
    // 第一步:把响应体解析成 JSON
    .then(res => res.json())
    // 第二步:拿到真正的数据对象
    .then(data => {
      console.log(data);
    });
}

async / await 写法:

async function getUser() {
  try {
    // 代码会在这里等待 fetch 完成
    const res = await fetch('https://api.example.com/user');
    // 代码会在这里等待 json 解析完成
    const data = await res.json();
    console.log(data);
  } catch (error) {
    // 使用 try...catch 来捕获异常
    console.error("请求失败", error);
  }
}

可以明显看到,使用 async/await 后,没有了回调函数的嵌套,代码阅读起来是从上往下直线的,非常清晰。

掌握了箭头函数、解构赋值、展开运算符以及 async/await,你就彻底拿到了阅读现代前端代码的“通行证”。接下来再去学习 Vue 3 或网络请求,将会如履平地。