JavaScript 基础

只讲 React 代码里常见的 JavaScript

要点

  • 在 React 里卡住的地方,大多不是 React,而是 JavaScript。这里分成数组函数、比较符号、写法三类整理
  • map、filter、...(展开)不会修改原数组,而是生成“新的数组”。所以和 React 的 state 很搭
  • 遇到不认识的写法,先读下表里一句话的“规则”,再到演示里试一试

速查表

数组的函数

写法规则(一句话)示例
.map((x) => …)逐个取出,生成一个变换后的新数组members.map((m) => <li>{m.name}</li>)
.filter((x) => 条件)生成只保留符合条件的元素的新数组members.filter((m) => m.plan === "付费")
.find((x) => 条件)返回第一个符合条件的元素members.find((m) => m.id === 2)
.sort((a, b) => 数字)两两比较来排序。结果为负数时 a 排在前面[...items].sort((a, b) => a.price - b.price)
.slice(开始, 结束)从开始截取到结束的前一个(从 0 开始数)items.slice(0, 6)
.reduce((合计, x) => …, 0)逐个查看,汇总成一个值(例如合计)items.reduce((sum, i) => sum + i.price, 0)
.includes(x)是否包含 x(true/false)name.includes(query)
.length数组是元素个数,字符串是字符数{members.length} 人
.some((x) => 条件)是否至少有一个符合条件(true/false)items.some((i) => i.stock === 0)
.join(分隔符)把数组用分隔符连接成一个字符串tags.join("、")

比较与连接

写法规则(一句话)示例
===左边和右边是否相同plan === "付费"
!==左边和右边是否不同m.id !== id
> >= < <=大于・大于等于・小于・小于等于quantity >= stock
!取反(true ↔ false)!isOpen
&&并且。在 JSX 中表示“符合就显示”{error && <p>{error}</p>}
||或者!isDirty || isSubmitting
条件 ? A : B符合就是 A,不符合就是 B{open ? "关闭" : "打开"}
a ?? ba 为空(null・undefined)时使用 buser.name ?? "游客"
a?.b即使 a 为空也不报错,而是得到 undefineduser?.name

写法

写法规则(一句话)示例
(x) => …创建函数(接收 x,执行 …)() => setCount(count + 1)
(x) => { … }里面可以写多行的函数onClick={() => { reset(); setSent(false) }}
const 和 letconst 不重新赋值,let 之后可以重新赋值let sorted = filtered
const [a, setA] = …给返回的两个值起名并取出const [count, setCount] = useState(0)
const { a, b } = …从对象({ })里按名字只取出要用的部分const { user } = useAuth()
function X({ a })按名字接收传给组件的值(props)function Card({ title }) { … }
`…${x}…`在字符串里插入值(模板字符串)`${count} 条`
[...x, 新增]复制数组,并在末尾追加后得到的新数组setMembers([...members, newMember])
{ ...x, 键: 值 }复制一个对象,只改一处后得到的新对象{ ...member, id: 7 }
import/export使用其他文件的组件/提供给其他文件使用import { Button } from "./button"
async/await等待耗时的操作(例如获取数据)完成const res = await fetch(url)

动手试试

import { useState } from "react"

// 会员列表(最初的 3 人)
const initialMembers = [
  { id: 1, name: "张伟", plan: "付费" },
  { id: 2, name: "李娜", plan: "免费" },
  { id: 3, name: "王芳", plan: "付费" },
]

export default function App() {
  // 会员列表(点“加 1 人”会增加)
  const [members, setMembers] = useState(initialMembers)
  // 是否按下了“只看付费”(true = 已按下)
  const [paidOnly, setPaidOnly] = useState(false)

  // 要显示的列表:按下了就只显示付费会员,没按就显示全部
  const shown = paidOnly ? members.filter((member) => member.plan === "付费") : members

  // 加 1 人:把现有会员全部排好,在最后加上 1 个新会员
  function addMember() {
    const newId = members.length + 1
    setMembers([...members, { id: newId, name: "会员" + newId, plan: "免费" }])
  }

  return (
    <div style={{ padding: 16, fontFamily: "sans-serif" }}>
      <div style={{ display: "flex", gap: 8 }}>
        {/* 每按一次,就在 只看付费 ↔ 全部 之间切换(! = 取反) */}
        <button onClick={() => setPaidOnly(!paidOnly)}>{paidOnly ? "查看全部" : "只看付费"}</button>
        <button onClick={() => addMember()}>加 1 人</button>
      </div>
      <p>共 {shown.length} 人</p>
      {/* 把要显示的列表,逐个变成“姓名(方案)”的一行 */}
      <ul>
        {shown.map((member) => (
          <li key={member.id}>
            {member.name}({member.plan})
          </li>
        ))}
      </ul>
    </div>
  )
}
  1. 点一下“只看付费”(filter 会生成只有付费会员的新数组)
  2. 把 "付费" 改成 "免费" 试试
  3. 多点几次“加 1 人”([...members, 新成员] 会在末尾逐个增加)

常见错误

用 members.push(人) 页面不会变
push 只是改写原数组,React 察觉不到变化。要用 [...members, 人] 生成新数组,再传给 setMembers。
.sort 会改写原数组
和 map、filter 不同,sort 会直接对原数组排序。要像 [...items].sort(…) 这样,先复制再排序。
= 是“赋值”,=== 是“是否相同”
如果在条件里写 =,不会比较,而是把值赋进去。比较时要用 ===。