跳至正文
来两杯美式
返回

前端核心(二):React 必备 JS 语法速查

By 来两杯美式
发布于

写 React 不需要精通 JS 全部语法,但有一组 ES6+ 特性你每天都会遇到。这篇文档把它们集中讲清楚,按出现频率排序。

一、解构赋值

从对象或数组里”拆”出值,给它们取名字。

1.1 对象解构:按名字取

const user = { name: "yi", age: 25, city: "Shanghai" };

// 按名字取值,顺序随意
const { age, name } = user;
// name → 'yi'
// age → 25

// 改名:把 name 改叫 userName
const { name: userName } = user;
// userName → 'yi'

// 取不存在的 key → undefined
const { email } = user;
// email → undefined

// 给默认值
const { email = "none" } = user;
// email → 'none'(因为 user 里没有 email)
// 为什么会没有?后端 JSON 序列化时,值为 null/空的字段常被省略,
// 前端拿到的对象里压根没那个 key,解构出来就是 undefined

React 里的样子——useQuery 返回对象,用对象解构接:

const { data, isPending, error } = useQuery({ ... })

1.2 数组解构:按位置取

const coords = [120, 31];

// 按位置对应,第几个就是第几个
const [lng, lat] = coords;
// lng → 120
// lat → 31

// 跳过某个位置
const [, lat] = coords;
// lat → 31,跳过第一个

// 给默认值
const [first, second, third = 0] = [1, 2];
// third → 0(数组里没有第三个元素)

React 里的样子——useState 返回数组,用数组解构接:

const [count, setCount] = useState(0);
//     ↑ 第一个    ↑ 第二个

1.3 为什么 useState 用数组、useQuery 用对象?

返回类型适合场景原因
数组 [a, b]返回值少且固定(2 个)简洁,你自由命名
对象 { a, b, c }返回值多(10+ 个)按名字取,不用记位置

useState 只返回 2 个东西,用数组短;useQuery 返回十几个字段,用对象才不会乱。

1.4 嵌套解构

两种可以组合使用:

const response = {
  data: { name: "yi" },
  meta: { page: 1, total: 100 },
};

// 对象里取 data,再从 data 里取 name
const {
  data: { name },
} = response;
// name → 'yi'

二、箭头函数

2.1 基本语法

// 普通函数
function add(a, b) {
  return a + b;
}

// 箭头函数
const add = (a, b) => {
  return a + b;
};

// 函数体只有一行时,省略大括号和 return
const add = (a, b) => a + b;

// 只有一个参数时,省略小括号
const double = n => n * 2;

// 没有参数时,必须写空括号
const sayHi = () => console.log("hi");

2.2 在 React 里为什么用箭头函数?

因为短。

// 箭头函数:一行搞定
onClick={() => setCount(count + 1)}

// 普通函数:啰嗦
onClick={function() { setCount(count + 1) }}

React 里到处都是回调——onClick、map、queryFn——箭头函数省掉 functionreturn,代码更紧凑。

2.3 this 的问题(面试常考,React 里感知不强)

箭头函数没有自己的 this,它从定义时的外层作用域继承 this

不适合当对象方法

const obj = {
  name: "yi",

  // ✅ 普通函数当方法:this 指向调用者 obj
  greet() {
    console.log(this.name);
  }, // 'yi'

  // ❌ 箭头函数当方法:this 继承外层作用域(全局/模块),不是 obj
  greetArrow: () => {
    console.log(this.name);
  }, // undefined
};

适合需要保留外层 this 的回调

const obj = {
  name: "yi",
  friends: ["Alice", "Bob"],

  // ✅ 箭头函数回调:this 继承 showFriends 的 this(即 obj)
  showFriends() {
    this.friends.forEach(friend => {
      console.log(this.name + " knows " + friend); // 正确!this 是 obj
    });
  },

  // ❌ 普通函数回调:this 取决于谁调用 forEach,不再是 obj
  showFriendsBroken() {
    this.friends.forEach(function (friend) {
      console.log(this.name + " knows " + friend); // 报错!this 不是 obj
    });
  },
};

但注意:React 函数组件里根本不用 this,所以这个特性你几乎感觉不到。真正受益的是 class 组件(现在很少写了)。this 相关的知识了解一下即可,面试会问,日常 React 开发不用操心。

2.4 React 里的样子

// 事件处理
<button onClick={() => setCount(count + 1)}>Click</button>;

// map 回调
{
  items.map(item => <li key={item.id}>{item.name}</li>);
}

// queryFn
useQuery({
  queryKey: ["user"],
  queryFn: () => fetch("/api/user").then(res => res.json()),
});

2.5 返回对象字面量的坑

箭头函数直接返回对象时,大括号会被当成函数体:

// ❌ 返回 undefined(大括号被当成函数体,label: 被当成标签语句)
const getUser = () => {
  name: "yi";
};

// ✅ 用括号包裹,告诉 JS 这是一个对象
const getUser = () => ({ name: "yi" });

三、展开运算符 ...

把对象或数组”拆开”铺平。

3.1 复制对象

const user = { name: "yi", age: 25 };

// 复制 + 覆盖某个字段
const updated = { ...user, age: 26 };
// → { name: 'yi', age: 26 }

// 添加新字段
const withEmail = { ...user, email: "yi@test.com" };
// → { name: 'yi', age: 25, email: 'yi@test.com' }

记住... 放前面是”复制原来的”,后面写的字段会覆盖前面的。

{ ...user, age: 26 }   // 复制 user,age 改成 26
{ age: 26, ...user }   // age: 26 被 user.age: 25 覆盖,结果还是 25

3.2 复制数组

const items = [1, 2, 3];

// 末尾加
const added = [...items, 4]; // [1, 2, 3, 4]

// 开头加
const prepended = [0, ...items]; // [0, 1, 2, 3]

// 合并
const merged = [...items, ...more]; // 拼接两个数组

3.3 React 里的样子

// 更新 state 对象
setUser({ ...user, age: 26 })

// 更新 state 数组
setItems([...items, newItem])              // 加
setItems(items.filter(i => i.id !== id))   // 删
setItems(items.map(i => i.id === id ? { ...i, done: true } : i)) // 改

// 传递 props
<Component {...defaultProps} extraProp="value" />

3.4 收集剩余参数

... 放在函数参数里,作用反过来——收集成数组:

function sum(...nums) {
  return nums.reduce((a, b) => a + b, 0);
}
sum(1, 2, 3); // 6

3.5 浅拷贝警告

... 只复制一层,嵌套的对象仍是引用:

const original = { name: "yi", address: { city: "Shanghai" } };
const copy = { ...original };

copy.address.city = "Beijing";
console.log(original.address.city); // 'Beijing' ← 原对象也被改了!

嵌套对象需要逐层展开:{ ...original, address: { ...original.address, city: 'Beijing' } }

四、可选链 ?.

访问可能为 nullundefined 的属性/方法,不会报错。

4.1 问题:直接点属性会崩溃

const user = undefined;
user.name; // ❌ TypeError: Cannot read property 'name' of undefined

4.2 解决:?. 遇到 undefined/ null 就短路

user?.name       // undefined(不报错)
user?.address?.city  // undefined(链式也安全)
items?.map(...)  // undefined(方法调用也安全)

等价于:

user && user.name; // 旧写法,啰嗦
user?.name; // 新写法,简洁

4.3 React 里的样子

// 渲染可能为空的数据
<div>{data?.user?.name}</div>;

// 调用可能不存在的方法
onClose?.();

// 访问数组元素
items?.[0]?.name;

五、空值合并 ??

左边是 nullundefined 时,用右边的值。

const name = null ?? "匿名"; // '匿名'
const name = undefined ?? "匿名"; // '匿名'
const name = "yi" ?? "匿名"; // 'yi'
const count = 0 ?? 10; // 0(0 不是 null/undefined)
const text = "" ?? "默认"; // ''(空字符串不是 null/undefined)

5.1 和 || 的区别

|| 对所有 falsy 值0''falsenullundefined)都会用右边:

const count = 0 || 10; // 10(0 是 falsy,用了右边)
const count = 0 ?? 10; // 0(0 不是 null/undefined,保留左边)

const text = "" || "默认"; // '默认'
const text = "" ?? "默认"; // ''(空字符串保留左边)

规律:需要保留 0''false → 用 ??;不需要 → 用 ||

5.2 React 里的样子

<div>{user?.name ?? '未登录'}</div>
<span>{remaining ?? ''}</span>

六、短路求值 &&||

利用 JS 的逻辑运算特性做条件判断——不是返回 true/false,而是返回决定结果的那个值

6.1 &&:左边为真 → 返回右边;左边为假 → 返回左边

true && "hello"; // 'hello'
false && "hello"; // false
1 && 2 && 3; // 3(全部为真,返回最后一个)
0 && "hello"; // 0(0 是 falsy,返回 0)

React 条件渲染——最常用的模式:

{
  isLoading && <Spinner />;
}
// isLoading=true  → 渲染 <Spinner />
// isLoading=false → 渲染 false(React 忽略,什么都不显示)

{
  items.length > 0 && <List items={items} />;
}
// 有数据才渲染列表

6.2 ||:左边为真 → 返回左边;左边为假 → 返回右边

"yi" || "默认"; // 'yi'
"" || "默认"; // '默认'
0 || 10; // 10
null || ""; // '无'

React 默认值

<div>{userName || "未登录"}</div>

七、三元表达式 ? :

一行写完 if-else,返回值。

const status = age >= 18 ? "成年" : "未成年";

等价于:

let status;
if (age >= 18) {
  status = "成年";
} else {
  status = "未成年";
}

7.1 React 条件渲染

{
  isLoggedIn ? <Dashboard /> : <LoginPage />;
}
{
  isPending ? "Loading..." : `${data.length}`;
}

7.2 可以嵌套,但别超过两层

// ✅ 两层还行
{
  status === "loading" ? (
    <Spinner />
  ) : status === "error" ? (
    <Error />
  ) : (
    <Content data={data} />
  );
}

// ❌ 再多层就改用 if-else 或抽组件

八、模板字符串

用反引号 ` 包裹,${} 里写表达式。

const name = "yi";
const age = 25;

// 旧写法:拼字符串
"Hello, " +
  name +
  "! Age: " +
  age
  // 模板字符串
  `Hello, ${name}! Age: ${age}`
  // ${} 里可以写任何表达式
  `Next year: ${age + 1}``Total: ${items.reduce((sum, i) => sum + i.price, 0)}`;

8.1 多行字符串

// 普通字符串不能换行
const html = "<div>\n  <p>Hello</p>\n</div>";

// 模板字符串直接换行
const html = `<div>
  <p>Hello</p>
</div>`;

九、async / await

Promise 的同步写法——详见 Promise 详解,这里只讲 React 里的用法。

9.1 基本用法

// async 标记函数为异步
async function fetchUser() {
  // await 等待 Promise 完成
  const res = await fetch("/api/user");
  const data = await res.json();
  return data;
}

9.2 React 里的样子

// useQuery 的 queryFn
useQuery({
  queryKey: ["user"],
  queryFn: async () => {
    const res = await fetch("/api/user");
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    return res.json();
  },
});

// useMutation 的 mutationFn
useMutation({
  mutationFn: async newTodo => {
    const res = await fetch("/api/todos", {
      method: "POST",
      body: JSON.stringify(newTodo),
    });
    return res.json();
  },
});

9.3 错误处理

// try/catch
async function fetchUser() {
  try {
    const res = await fetch("/api/user");
    return await res.json();
  } catch (err) {
    console.error(err);
  }
}

十、数组方法

10.1 map —— 变换每个元素,返回新数组

React 列表渲染的核心:

const items = [
  { id: 1, name: 'Apple' },
  { id: 2, name: 'Banana' },
]

// JSX 列表渲染(必须加 key)
<ul>
  {items.map(item => (
    <li key={item.id}>{item.name}</li>
  ))}
</ul>
// 纯数据变换
const names = items.map(item => item.name);
// ['Apple', 'Banana']

const withPrice = items.map(item => ({ ...item, price: 10 }));
// [{ id: 1, name: 'Apple', price: 10 }, ...]

10.2 filter —— 按条件筛选,返回新数组

const nums = [1, 2, 3, 4, 5];
const evens = nums.filter(n => n % 2 === 0);
// [2, 4]

// 删除数组中的某项(React state 更新)
setItems(items.filter(i => i.id !== deletedId));

10.3 find —— 找第一个符合条件的元素

const items = [
  { id: 1, name: "A" },
  { id: 2, name: "B" },
];
const item = items.find(i => i.id === 2);
// { id: 2, name: 'B' }

const notFound = items.find(i => i.id === 99);
// undefined

10.4 some / every —— 是否有/全部满足条件

const ages = [18, 25, 30];

ages.some(a => a < 20); // true(至少有一个 < 20)
ages.every(a => a >= 18); // true(全部 >= 18)

10.5 reduce —— 累计计算

const prices = [10, 20, 30];
const total = prices.reduce((sum, price) => sum + price, 0);
// 60

// 第一个参数:累计函数
// 第二个参数:初始值(0)

10.6 它们都不修改原数组

mapfilterfindsomeeveryreduce 全部返回新值,不改变原数组。这和 React 的不可变性原则天然契合。


速查表

语法一句话React 里怎么用
解构 { } [ ]从对象/数组里取值useQuery 返回值 / useState 返回值
箭头函数 =>更简洁的函数,没有自己的 this事件处理、map 回调、queryFn
展开 …复制对象/数组更新 state:展开旧值再覆盖
可选链 ?.安全访问可能为空的属性data?.user?.name
空值合并 ??左边是 null/undefined 用右边name ?? ‘默认’
短路 &&左边为真才看右边loading && Spinner
三元 ? :一行 if-elseok ? A组件 : B组件
模板字符串字符串插值Hello, ${name}
async/awaitPromise 的同步写法queryFn、mutationFn
map / filter遍历/筛选数组列表渲染、state 更新

分享这篇文章:
通过邮件分享这篇文章✓ 链接已复制
查看系列全部文章
  1. 01.前端核心(一):DOM 入门
  2. 02.前端核心(二):React 必备 JS 语法速查
  3. 03.前端核心(三):Promise 与异步编程详解
  4. 04.前端核心(四):React 必备 TS 语法速查

上一篇
前端核心(三):Promise 与异步编程详解
下一篇
前端核心(一):DOM 入门