跳到主要內容

FE Day 6 狀態與事件:useState 與互動處理

FE Day 6 狀態與事件:useState 與互動處理

執行需求:CPU 可跑。今天是「前端開發實戰:React 與 Next.js 全套」系列的第六篇。Day 5 我們把元件、props、JSX 的基礎打好了,但寫出來的元件都是「死的展示」——給什麼 props 就顯示什麼內容,沒有互動。今天要把元件變成「活的」:用 useState 管理狀態、用事件處理接使用者操作、用 React 19 的新模式寫出簡潔的互動。讀完之後,你應該能寫出「按按鈕切換」、「輸入框受控」、「計數器」這些基礎互動,並理解 React 為什麼要把「狀態」託管起來。整篇閱讀時間約三十分鐘,動手做約二十五分鐘。

引言

後端工程師第一次接觸 React 的狀態(state),常會有一個疑惑:「為什麼前端需要『狀態』這種東西?後端的變數不就是狀態嗎?」這是個好問題——React 的狀態確實對應到後端的「會隨時間變化的資料」,但它被特殊對待的原因有兩個:第一,React 元件函式會被反覆執行(每次 render 都跑一次),如果用普通變數存狀態,每次 render 都會被重置;第二,使用者看到的畫面是「狀態的投影」,React 需要在狀態改變時自動重新渲染元件,這套機制必須由 React 自己管理。

今天的目標有五個:第一,理解「props vs state」的差別——前者是「父給子的」,後者是「元件自己管理的」;第二,useState 的兩種呼叫方式(給初始值、給 lazy initializer)與更新函式(直接給值、給函式);第三,事件處理的綁定方式與 this 陷阱(函式元件沒有這個問題);第四,受控元件 vs 非受控元件的概念;第五,常見的狀態陷阱(直接修改、忘記 cleanup、初始昂貴計算)。最後我們會用一個「預約篩選器」把前述觀念串起來:使用者輸入文字、即時過濾預約清單。

props vs state:兩個完全不同的資料來源

props 與 state 是 React 元件裡「資料」的兩種來源,理解它們的差別能幫助你決定「該把資料放在哪」。

props 是「父元件傳下來的」。元件本身不能改 props;如果要改,必須請父元件改(透過事件回呼)。props 的設計哲學是「資料流是單向的」——父層決定給什麼,子層只能用。Day 5 提過 props 是唯讀的,這條規則讓 React 能精準地知道「誰是資料的擁有者」。

state 是「元件自己擁有的」。元件透過 useState 宣告一段自己管理的狀態,呼叫更新函式就能改變它。改變時 React 會自動重新渲染元件、把新狀態帶回畫面。state 的設計哲學是「元件有獨立的內部狀態」——例如「目前是否展開」、「輸入框文字」、「選中的條目」。

特性 props state
擁有者 父元件 元件自己
可否修改 不可(唯讀) 可以(透過 setter)
觸發重渲染 父層重新渲染並傳新值 呼叫 setter
典型用途 外部資料、外部設定 UI 暫時狀態、表單輸入、切換

一個判斷原則:「如果這個資料是元件自己內部用的,就放 state;如果是被父層決定的,就放 props」。實務上常見的「狀態提升」(lifting state up)就是「把子層的 state 移到共同父層」——當兩個兄弟元件需要共享同一份資料時,把 state 提升到最近的共同祖先,再以 props 形式傳給兩個子層。Day 11 會專門展開 Context 與提升模式的取捨。

useState:最基本的 Hook

useState 是 React 內建的第一個 Hook,也是最常用的。它的功能是「讓元件擁有一段會隨時間變化的狀態」。呼叫一次 useState 回傳兩個值:目前狀態、與更新狀態的函式。

// src/components/Counter.tsx
// 最小的 useState:計數器
import { useState } from "react";

export function Counter() {
  // useState 回傳 [目前狀態, 更新函式]
  const [count, setCount] = useState(0);

  return (
    <div className="flex items-center gap-3">
      <p className="text-xl">目前數字:{count}</p>
      <button
        type="button"
        onClick={() => setCount(count + 1)}
        className="rounded bg-slate-900 px-3 py-1 text-white"
      >
        +1
      </button>
    </div>
  );
}

這支 Counter 元件展示 useState 三個關鍵:第一,useState(0) 傳入「初始值」,第一次 render 時 count 是 0;第二,setCount(count + 1) 是「設定新值」,React 收到後會重新渲染元件、把新的 count 帶回畫面;第三,onClick={() => setCount(count + 1)} 是事件處理——按下按鈕時 React 呼叫這個函式,於是 count 改變、畫面更新。後端工程師可以把它想成「在瀏覽器跑的計數器」:每次按按鈕,「全域變數 +1」並把新值印出來。

兩種更新方式:直接給值 vs 給函式

setCount 有兩種用法:直接給新值、給一個「根據舊值計算新值」的函式。後者在「連續操作」、「依賴前一個狀態」的情境特別重要:

// src/components/BetterCounter.tsx
// 用函式更新:保證拿到的是「最新」狀態
import { useState } from "react";

export function BetterCounter() {
  const [count, setCount] = useState(0);

  // 錯誤示範(在新版 React 通常能正確運作,但寫法依賴閉包):
  // const handleTriple = () => {
  //   setCount(count + 1);
  //   setCount(count + 1);
  //   setCount(count + 1);
  // };

  // 正確示範:用函式更新,保證每次都拿到最新值
  const handleTriple = () => {
    setCount((prev) => prev + 1);
    setCount((prev) => prev + 1);
    setCount((prev) => prev + 1);
  };

  return (
    <div className="flex items-center gap-3">
      <p className="text-xl">目前:{count}</p>
      <button
        type="button"
        onClick={handleTriple}
        className="rounded bg-emerald-600 px-3 py-1 text-white"
      >
        +3
      </button>
    </div>
  );
}

當你在同一個事件裡呼叫三次 setCount,如果用 setCount(count + 1),三次看到的 count 都是「事件開始時的值」(例如 0),最後結果會是 1(只加了一次)。用 setCount((prev) => prev + 1),React 會把更新排進佇列、依序套用,最後結果是 3。

實務上的判斷原則:「如果新值依賴舊值,就用函式更新」;「如果新值跟舊值無關,就直接給值」。例如 setText("") 是直接給值;setCount((c) => c + 1) 是函式更新。React 19 的官方文件明確建議「一律用函式更新」避免閉包陷阱。TypeScript 對這兩種簽名都能正確推論,所以不用擔心型別問題。

Lazy initializer:昂貴的初始值

當 useState 的初始值需要「昂貴計算」時(例如讀 localStorage、解析 JSON、計算衍生資料),可以用 lazy initializer:

// src/components/StickyNote.tsx
// 用 lazy initializer:只在第一次 render 讀 localStorage
import { useState } from "react";

function loadNote(): string {
  // 假設這步很貴:讀 localStorage、解析 JSON
  if (typeof window === "undefined") return "";
  const saved = localStorage.getItem("sticky-note");
  return saved ?? "";
}

export function StickyNote() {
  // 傳函式而不是值:只在第一次 render 執行 loadNote
  const [note, setNote] = useState<string>(loadNote);

  return (
    <div className="rounded border p-4">
      <h3 className="mb-2 font-semibold">便利貼</h3>
      <textarea
        className="w-full rounded border p-2"
        rows={4}
        value={note}
        onChange={(e) => setNote(e.target.value)}
      />
    </div>
  );
}

useState(loadNote) 的意思是「呼叫 loadNote 拿初始值」。注意是「傳函式」而不是「呼叫函式」:寫成 useState(loadNote()) 會讓 loadNote 每次 render 都跑一次,效能浪費。React 19 對這個差異有更嚴格的檢查:如果你不小心傳了呼叫結果(值),TypeScript 推論出來會跟預期不同。Day 10 自訂 Hook 時會大量使用這個模式。

事件處理:把使用者操作接上元件

React 的事件處理跟原生 DOM 很像,但有兩個重要差別。第一,事件命名用駝峰:onclick → onClick、onchange → onChange、onsubmit → onSubmit。第二,事件處理函式接收的是「SyntheticEvent」,這是 React 包裝過的事件物件,介面跟原生 Event 幾乎相同,但有跨瀏覽器一致性與效能改善。

// src/components/NameForm.tsx
// 事件處理:onChange 與 onSubmit
import { useState } from "react";

export function NameForm() {
  const [name, setName] = useState("");
  const [submitted, setSubmitted] = useState<string | null>(null);

  // onChange:每次輸入框改變時觸發
  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setName(e.target.value);
  };

  // onSubmit:表單送出時觸發
  const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();  // 阻止預設行為(不要重新載入頁面)
    setSubmitted(name);
    setName("");         // 清空輸入框
  };

  return (
    <form onSubmit={handleSubmit} className="space-y-3">
      <label className="block">
        <span className="text-sm text-slate-600">姓名</span>
        <input
          type="text"
          value={name}
          onChange={handleChange}
          className="mt-1 block w-full rounded border px-3 py-2"
        />
      </label>
      <button type="submit" className="rounded bg-slate-900 px-4 py-2 text-white">
        送出
      </button>
      {submitted && (
        <p className="text-emerald-600">你好,{submitted}!</p>
      )}
    </form>
  );
}

這支表單展示了四個重點:第一,onChange 接的是 React.ChangeEvent,泛型指定是哪一種元素;第二,e.preventDefault() 阻止表單送出的預設行為(重新載入頁面),這是 React 表單的標準慣例;第三,value={name} 讓輸入框變「受控元件」(value 由 state 控制);第四,按下 Enter 也會觸發 submit,這是 form 元素的預設行為。函式元件沒有 this 綁定問題,事件處理函式可以直接寫,不必像 class 元件那樣 bind。

受控 vs 非受控元件

React 表單有兩種管理輸入值的方式:

  • 受控元件:value 由 React state 控制,onChange 同步更新 state。React 是「single source of truth」。
  • 非受控元件:value 由 DOM 自己管,React 用 ref 在需要的時候讀取值。DOM 是「source of truth」。

實務上 React 社群推薦「一律用受控元件」:好處是可以即時驗證、可以根據輸入動態改 UI(例如禁用按鈕)、可以跟其他 state 連動。壞處是每次輸入都會 re-render 元件,但對小型表單影響微乎其微。Day 12 會專門展開表單處理,包含 React 19 的 useActionState 與表單函式庫。

事件處理有兩個實務細節值得記住。第一,事件處理函式如果需要傳參數,常見寫法是用 closure:onClick={() => handleDelete(item.id)}。第二,事件物件(SyntheticEvent)會在事件處理結束後被 React 回收(出於效能考量),所以不能在非同步操作裡讀取它。如果要在 setTimeout 或 fetch 之後讀取,必須先 e.persist() 或把需要的欄位複製出來。

完整實作:預約篩選器

把前面學的 useState、事件處理、受控元件整合起來:寫一個「預約篩選器」,使用者輸入文字、即時過濾預約清單:

// src/features/booking/BookingFilter.tsx
// 預約篩選器:受控輸入框 + 過濾邏輯
import { useState } from "react";
import type { Booking } from "../../types/booking";

type BookingFilterProps = {
  bookings: Booking[];
};

// 這個元件的狀態:使用者輸入的篩選字串
export function BookingFilter({ bookings }: BookingFilterProps) {
  const [keyword, setKeyword] = useState("");

  // 根據 keyword 過濾 bookings
  // 注意:每次 render 都會重算(小型資料 OK;大型資料要用 useMemo)
  const filtered = bookings.filter((booking) => {
    if (keyword === "") return true;
    return (
      booking.customerName.includes(keyword) ||
      booking.customerPhone.includes(keyword)
    );
  });

  return (
    <div className="space-y-4">
      <label className="block">
        <span className="text-sm text-slate-600">搜尋(姓名或電話)</span>
        <input
          type="search"
          value={keyword}
          onChange={(e) => setKeyword(e.target.value)}
          placeholder="輸入姓名或電話"
          className="mt-1 block w-full rounded border px-3 py-2"
        />
      </label>

      <p className="text-sm text-slate-500">
        共 {filtered.length} 筆(總共 {bookings.length} 筆)
      </p>

      <ul className="divide-y rounded border">
        {filtered.map((booking) => (
          <li key={booking.id} className="p-3">
            <p className="font-medium">{booking.customerName}</p>
            <p className="text-sm text-slate-600">
              {booking.customerPhone}・{booking.startAt}
            </p>
          </li>
        ))}
      </ul>
    </div>
  );
}

這支元件展示五個整合觀念:第一,useState("") 是「受控輸入框」的基本寫法;第二,onChange={(e) => setKeyword(e.target.value)} 把使用者輸入即時同步到 state;第三,bookings.filter(...) 每次 render 都重算,但因為 bookings 沒變,React 只重畫 DOM 變動的部分;第四,key={booking.id} 讓 React 正確識別每個清單條目(Day 7 會展開);第五,「共 N 筆(總共 M 筆)」這個統計區塊會隨著 keyword 變化即時更新,這就是 state 帶動 UI 改變的最直觀示範。

多狀態元件:tab 切換器

實務上元件常常需要管理「多個獨立的狀態」。React 鼓勵「一個 useState 管一件事」而不是把全部塞進一個物件。下面是一個「頁籤切換器」範例,示範多狀態元件的設計:

// src/components/Tabs.tsx
// 多狀態元件:頁籤切換器
import { useState } from "react";

type Tab = { id: string; label: string; content: string };
const tabs: Tab[] = [
  { id: "info", label: "預約資訊", content: "本週預約總覽" },
  { id: "stats", label: "統計", content: "已完成 12 筆、待確認 3 筆" },
  { id: "settings", label: "設定", content: "通知偏好與時區" },
];

export function Tabs() {
  // 拆分為獨立 state:每個 state 只管一件事
  const [activeId, setActiveId] = useState(tabs[0]!.id);

  // 根據 activeId 找到當前頁籤
  const active = tabs.find((t) => t.id === activeId) ?? tabs[0]!;

  return (
    <div>
      {/* 頁籤按鈕列 */}
      <div role="tablist" className="flex border-b">
        {tabs.map((tab) => (
          <button
            key={tab.id}
            type="button"
            role="tab"
            aria-selected={tab.id === activeId}
            onClick={() => setActiveId(tab.id)}
            className={[
              "px-4 py-2 text-sm",
              tab.id === activeId
                ? "border-b-2 border-slate-900 font-semibold"
                : "text-slate-500",
            ].join(" ")}
          >
            {tab.label}
          </button>
        ))}
      </div>

      {/* 頁籤內容 */}
      <div role="tabpanel" className="p-4">
        <p>{active.content}</p>
      </div>
    </div>
  );
}

這支 Tabs 元件展示三個細節:第一,activeId 與計算出來的 active 拆分——前者存「狀態」、後者存「衍生資料」,避免資料不一致;第二,role="tablist"、role="tab"、role="tabpanel"、aria-selected 是 WAI-ARIA 的標準屬性,讓螢幕閱讀器能正確辨識頁籤結構(Day 28 會展開無障礙);第三,tabs[0]! 後面的 ! 是 TypeScript 的「非空斷言」——因為陣列是靜態已知、不可能空,所以用 ! 把 undefined 排除掉。

另一個常見的「多狀態元件」是表單:姓名、電話、地址、備註各管一個 state。當某個欄位改變時,只有該 state 訂閱的子元件會重渲染,其他欄位不受影響。Day 13 會展開「如何把 state 拆分得更細」,避免「一個欄位改變、整個表單重渲染」這種效能陷阱。Day 11 則會談 Context 與狀態管理——當多個深層子元件需要共用一份狀態時,怎麼避免層層 props 傳遞。

常見錯誤與踩雷

第一次寫 useState 與事件處理,最常踩的雷有四個。第一個是「直接修改 state」。count = 5 不會觸發重渲染,必須用 setCount(5)。React 的設計是「state 不可變」(immutable),必須透過 setter 改。後端寫過 OOP 的人會覺得「為什麼不直接改物件」——這是 React 為了「diff 演算法」設計的規則,Day 7 會展開。對陣列與物件也是一樣:不能 items.push(...),必須用 setItems([...items, newItem])。

第二個是「忘記 bind 事件處理器」。這是 class 元件的舊問題,函式元件沒這個困擾。如果你在舊專案看到 this.handleClick = this.handleClick.bind(this),那是 class 元件時代的 workaround。函式元件可以直接寫 onClick={handleClick},因為函式沒有 this。

第三個是「把 setState 寫進 render 裡」。如果元件本體裡直接呼叫 setCount(count + 1),每次 render 都會觸發 setState、導致無限迴圈。修法是把 setState 放進事件處理器或 useEffect(Day 9)。這是 React 新手最容易踩的雷之一,記住「render 是純函式、不能有副作用」就對了。另一個延伸陷阱是「在 useEffect 裡 setState 卻沒設依賴」,會造成資料不同步或重複觸發。

第四個是「同步讀取 state 變更後的值」。因為 React 的 state 更新是非同步的(會批次處理),呼叫 setCount(5) 之後,下一行讀 count 仍是舊值。如果需要根據新值做事(例如送出表單後清空輸入框),要用函式更新或在 callback 裡操作。

效能與實務提醒

今天寫的 BookingFilter 有個潛在的效能問題:bookings.filter 每次 render 都會跑一次。如果 bookings 有幾千筆、輸入框每次按鍵都會觸發 re-render,效能會開始感受到延遲。修法有兩個方向:第一,用 useMemo 把計算結果記住,只有 bookings 或 keyword 變動時才重算;第二,把 keyword 的更新加上 debounce(延遲 200 毫秒才更新 state),降低 re-render 頻率。Day 10 與 Day 13 會展開這兩個技巧。

另一個實務提醒是「state 拆分」。很多人會把所有資料塞進一個 state 物件,例如 const [form, setForm] = useState({ name: "", email: "", phone: "" }),然後每次輸入都 setForm({ ...form, [e.target.name]: e.target.value })。這種寫法在小表單 OK,但欄位變多就難維護。建議把獨立變化的欄位拆成獨立的 useState,例如 useState("") 三次;當某個欄位改變時,只有對應的元件訂閱者會 re-render。Day 13 會展開狀態管理策略。

最後一個提醒是「state 提升」。當兩個兄弟元件需要共享同一份資料(例如「選中的預約 ID」),把這份 state 放在共同父層,再以 props 形式傳給兩個子層。常見的「全選 / 取消全選」、「目前選中的條目」都是這種模式。React 19 之後還能用 Context(Day 11)把這層提升跳過,但 Context 不是萬靈丹——props 仍是首選,Context 是次優解。

React 19 的新 Hook 簡介

React 19 除了 useState 之外,還引入了幾個與狀態/互動相關的新 Hook,這裡先簡介概念,後續 Day 9、Day 12、Day 21 會詳細展開。

第一個是 useActionState。它的設計是把「表單送出」這種「開始 → 等待 → 完成/失敗」的狀態流整合成一個 Hook,避免用 useState + useEffect 拼出來:

// src/features/booking/SubmitButton.tsx
// React 19 的 useActionState:表單送出的 pending / result / error
import { useActionState } from "react";

// action 函式:真正執行送出
async function submitBooking(
  prev: { ok: boolean; message: string } | null,
  formData: FormData,
) {
  const name = formData.get("customerName");
  // 呼叫 API...
  return { ok: true, message: `已為 ${name} 建立預約` };
}

export function SubmitButton() {
  const [state, formAction, isPending] = useActionState(submitBooking, null);

  return (
    <form action={formAction} className="space-y-3">
      <input
        type="text"
        name="customerName"
        placeholder="顧客姓名"
        className="rounded border px-3 py-2"
      />
      <button
        type="submit"
        disabled={isPending}
        className="rounded bg-slate-900 px-4 py-2 text-white disabled:opacity-50"
      >
        {isPending ? "送出中…" : "建立預約"}
      </button>
      {state && (
        <p className={state.ok ? "text-emerald-600" : "text-red-600"}>
          {state.message}
        </p>
      )}
    </form>
  );
}

useActionState 回傳三個值:「上一次結果」、「給 form action 用的函式」、「是否正在送出中」。這讓表單元件不用自己管理三個 useState(結果、pending、錯誤),邏輯全部集中在 action 函式。Day 12 與 Day 21 會展開完整的表單處理。

第二個是 useOptimistic。它讓你「假裝操作已經成功」,先更新畫面,等伺服器回應後再修正。常用在「按讚」、「加到購物車」、「預約送出」這種「使用者期待即時回饋」的情境:

// src/features/booking/OptimisticBooking.tsx
// React 19 的 useOptimistic:送出時先顯示「待確認」
import { useOptimistic, useState } from "react";
import type { Booking } from "../../types/booking";

type Props = { bookings: Booking[] };

export function OptimisticBooking({ bookings }: Props) {
  // 真實的 bookings:來自伺服器
  const [real, setReal] = useState(bookings);

  // 樂觀的 bookings:等待 API 回應時的「假裝」狀態
  const [optimistic, addOptimistic] = useOptimistic(
    real,
    (current, newBooking: Booking) => [...current, newBooking],
  );

  async function handleAdd(formData: FormData) {
    const newBooking: Booking = {
      id: Math.random(),
      customerName: String(formData.get("name")),
      customerPhone: String(formData.get("phone")),
      serviceId: 1,
      startAt: "2026-03-25T10:00:00+08:00",
      status: "pending",
      createdAt: new Date().toISOString(),
      updatedAt: new Date().toISOString(),
    };

    // 先在畫面顯示新預約(樂觀更新)
    addOptimistic(newBooking);

    // 實際呼叫 API,成功後用真實資料覆蓋
    await fetch("/api/bookings", {
      method: "POST",
      body: JSON.stringify(newBooking),
    });
    setReal([...real, newBooking]);
  }

  return (
    <div>
      {/* 用 optimistic 渲染清單,給使用者即時回饋 */}
      <p>目前顯示 {optimistic.length} 筆</p>
      <form action={handleAdd}>
        <input name="name" placeholder="姓名" />
        <input name="phone" placeholder="電話" />
        <button type="submit">新增</button>
      </form>
    </div>
  );
}

useOptimistic 的精髓是「使用者動作 → 立即更新畫面 → 背景打 API → 成功就保留、失敗就回滾」。這對「按讚數立刻 +1」、「預約立刻出現在清單」這種 UX 提升非常明顯。Day 21 的 Server Actions 會再次用上這個 Hook。本系列 Day 12 表單與 Day 21 表單 + Server Actions 會完整展開這兩個 Hook。

小結

今天我們把元件變活了:props 與 state 的差別、useState 的兩種呼叫方式與更新函式、事件處理的駝峰命名與 SyntheticEvent、受控 vs 非受控元件的選擇,並用一個完整的「預約篩選器」把這些觀念串起來。明天 Day 7 我們會進入渲染模型:條件渲染、清單渲染、key 的角色——理解 React 怎麼決定「哪些 DOM 要重畫、哪些不動」。這是「React 為什麼快」的底層觀念,學完會對 props/state 的設計有更深一層理解。

結語

明天,我們會把渲染模型一次學完:為什麼同一個元件 render 多次對 React 來說是常態、reconciliation 演算法怎麼決定要更新哪些 DOM、清單為什麼一定要給 key、key 錯了會發生什麼事。Day 7 結束時,你寫的清單渲染就能避開「為什麼這筆刪不掉」、「為什麼這欄錯亂」等經典 bug。接著 Day 8 進入樣式方案——Tailwind CSS 4 與設計慣例。

延伸資源

  • React 官方〈State: A Component's Memory〉:https://react.dev/learn/state-a-components-memory
  • React 官方〈Responding to Events〉:https://react.dev/learn/responding-to-events
  • React 官方〈Choosing the State Structure〉:https://react.dev/learn/choosing-the-state-structure
  • React 官方〈Sharing State Between Components〉:https://react.dev/learn/sharing-state-between-components
  • MDN〈React 互動式教學〉:https://developer.mozilla.org/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_interactivity_filtering_conditional_rendering

留言

這個網誌中的熱門文章

Day 2 變數與資料型別

Day 2 變數與資料型別 引言 寫程式的過程中,變數與資料型別是處理資料的基礎。變數是存放資料的容器,資料型別則決定這筆資料有哪些特性、可以進行哪些操作。學會定義變數、認識各種資料型別,是學好 Python 的關鍵一步。 這篇文章會帶你了解 Python 中變數的觀念、如何定義變數,以及常見的資料型別,包括整數、浮點數、字串、布林值,還有串列、元組、字典與集合等容器型別。我們也會介紹變數的命名規則與撰寫風格建議,以及如何用 type() 檢查資料型別。 什麼是變數?如何在 Python 中定義變數 變數是在程式執行時用來存放資料的名稱。透過定義變數,我們可以給一筆資料一個名字,並在程式的其他地方用這個名字取用該筆資料。在 Python 中,變數不需要事先宣告型別,因為 Python 是動態型別語言,變數的型別由指定給它的值決定。 定義變數的基本語法 在 Python 中定義變數非常簡單,只要用賦值符號 = 把值指定給變數即可。例如: x = 5 # 定義變數 x,並把整數 5 賦值給它 name = "Alice" # 定義變數 name,並把字串 "Alice" 賦值給它 在這裡,x 是一個變數,被賦予整數 5;name 是另一個變數,被賦予字串 "Alice"。 變數的更新與覆寫 變數的值可以修改,也就是說,我們可以在程式的不同地方給同一個變數新的值。例如: x = 10 # x 最初被賦予 10 x = 15 # x 的值現在被更新為 15 這樣就能依照需求,在程式執行過程中靈活調整變數的值。 Python 的動態型別系統 Python 和某些靜態型別語言不同,定義變數時不需要宣告型別。賦值時,Python 會根據值自動判斷變數的型別。例如: x = 5 # x 是整數 x = 3.14 # x 變成浮點數 x = "Hi" # x 變成字串 同一個變數在程式執行過程中可以存放不同型別的值,這是 Python 的彈性之一。 常見資料型別 在 Python 中,資料型別決定我們可以對變數進行哪些操作...

Python 從入門到 PyTorch 深度學習:開啟 AI 世界的大門

Python 從入門到 PyTorch 深度學習:開啟 AI 世界的大門 隨著人工智慧(AI)與深度學習(Deep Learning)快速發展,越來越多人對這些技術產生興趣。不論你是想踏入 AI 領域的初學者,還是已經有程式基礎的開發者,學好 Python 與深度學習框架(例如 PyTorch),都能為你打開更多可能。 為什麼選擇 Python? Python 已經是資料科學與人工智慧領域的首選語言。它的語法簡潔、容易上手,而且擁有龐大的生態系與大量開源函式庫。無論是資料處理、資料視覺化,還是建立機器學習與深度學習模型,Python 都能勝任。對想進入 AI 或資料科學領域的人來說,它幾乎是必備工具。 PyTorch 是什麼? PyTorch 是由 Meta(原 Facebook)AI 研究團隊開發的開源深度學習框架,以易用、靈活和動態計算圖著稱,是許多 AI 研究人員與開發者的首選。相較於其他框架,PyTorch 的寫法更貼近原生 Python,對初學者相對友善。無論是簡單的實驗,還是複雜的深度學習模型,PyTorch 都能提供強大的支援。 這個系列能帶給你什麼? 這個系列會從 Python 的基礎開始,帶你一步一步學習,最後能自己用 PyTorch 建立深度學習模型。即使你完全沒有寫過程式,也能跟著文章的節奏累積技能,理解 AI 與深度學習的核心觀念。 本系列涵蓋的主題 Python 基礎:從變數、條件判斷到函式與模組。 資料處理工具:用 NumPy 與 Pandas 有效率地操作資料。 資料視覺化:用 Matplotlib 與 Seaborn 把資料畫成圖表。 深度學習的數學基礎:線性代數、微積分與機率。 PyTorch 入門:理解張量、模型建構與 GPU 加速。 基礎深度學習模型:CNN 與 RNN 的實作應用。 深度學習專案實戰:從資料前處理到模型部署的端到端流程。 誰適合這個系列? 程式初學者 :如果你對 AI 充滿好奇,卻還沒寫過程式,系列的第一部分會帶你快速上手 Python,並幫助你理解深度學習的基本觀念。 資料科學愛好者 :如果你已經熟悉一些資料處理方法,進階部分會教你如何用 PyTorch 建構深度學習模型。 開發者與研究人員 :想更深入了...

Day 1 Python 簡介與環境設定

Day 1 Python 簡介與環境設定 引言 在現在的科技環境裡,程式設計已經是一項重要技能。無論你是對資料科學有興趣、想成為開發者,或是想踏入人工智慧(AI)領域,學會寫程式都能明顯提升你的競爭力。在眾多程式語言中,Python 因為語法簡單、功能強大、應用範圍廣泛,成為許多人進入程式世界的第一選擇。這篇文章會帶你認識 Python 的背景與優勢,並一步步教你在不同系統上安裝與設定 Python 開發環境,最後寫出第一支 Python 程式。 為什麼選擇 Python? Python 是一種高階程式語言,由 Guido van Rossum 在 1991 年發布。Python 的設計哲學強調程式碼的可讀性,並用縮排來定義程式區塊,這點和許多使用大括號的語言不同。簡潔的語法讓它成為初學者的理想選擇;就算是經驗豐富的開發者,也能用它完成複雜的專案。 Python 的優勢如下: 簡單易學 :Python 的語法清楚、結構簡潔,初學者很快就能上手。和其他語言相比,學習曲線相對平緩,不需要先弄懂一堆複雜觀念,就能開始寫程式。 應用範圍廣泛 :從資料科學、網頁開發、人工智慧、機器學習、自動化測試到網路爬蟲,Python 都有大量開源函式庫與工具支援,而且在這些領域都扮演關鍵角色。 豐富的函式庫與框架 :Python 的函式庫生態系非常龐大。做資料分析有 NumPy、Pandas;開發網站有 Django、Flask;做深度學習有 TensorFlow、PyTorch。各種需求幾乎都能找到對應的套件,讓開發更有效率。 跨平台支援 :Python 支援 Windows、macOS、Linux 等作業系統,程式通常不需要太多修改就能跨平台執行,讓開發與部署更有彈性。 活躍的社群 :Python 擁有龐大的開發者社群。學習或開發上遇到問題,幾乎都能在社群與論壇(例如 Stack Overflow)找到答案,對初學者來說是很強的後盾,也能減少卡關時的挫折感。 Python 的應用領域 Python 的流行與強大功能,讓許多領域都開始大量使用它。以下是幾個常見的應用方向: 資料科學 :隨著大數據與人工智慧興起,資料科學大量使用 Python。NumPy、Pandas 與 Matplotlib 等工具能處理和分析龐...