學(xué)習(xí) React 前,你必須掌握的 10 個 JavaScript 核心概念
學(xué)習(xí) React 前,你必須掌握的 10 個 JavaScript 核心概念
如果你正計劃入門 React.js,先稍等一下 —— 問問自己:“我的 JavaScript 基礎(chǔ)真的扎實嗎?”
React 并非寫過幾行 JS 就能直接上手的框架。它要求你清楚 JavaScript 的底層工作原理,尤其是那些看似簡單、卻支撐著整個 React 生態(tài)的核心概念。
下面就為大家詳細(xì)拆解,每個 React 開發(fā)者在寫出第一個 JSX 之前,必須掌握的 10 個 JavaScript 核心概念。
?? 1. let、const 與 var
在 React 中,你會頻繁聲明變量。但如果使用不當(dāng),很容易引發(fā)難以排查的 bug。理解這三者的作用域規(guī)則、重聲明限制以及暫時性死區(qū),能幫你節(jié)省大量調(diào)試時間。
示例:三者的區(qū)別與應(yīng)用場景
// var:函數(shù)級/全局作用域,存在變量提升,可重復(fù)聲明
console.log(name); // 輸出 undefined(變量提升但未賦值)
var name = "張三";
function testVar() {
var name = "李四"; // 函數(shù)內(nèi)重聲明,不影響外部
console.log(name); // 輸出 李四
}
testVar();
console.log(name); // 輸出 張三
// let:塊級作用域,無變量提升,存在暫時性死區(qū),不可重復(fù)聲明
console.log(age); // 報錯(暫時性死區(qū),無法訪問未初始化的let變量)
let age = 25;
if (true) {
let age = 30; // 塊內(nèi)聲明,不影響外部
console.log(age); // 輸出 30
}
console.log(age); // 輸出 25
// const:塊級作用域,必須初始化,不可重新賦值(引用類型內(nèi)部可修改)
const PI = 3.14159;
PI = 3.14; // 報錯(常量不可重新賦值)
const user = { name: "王五" };
user.name = "趙六"; // 可行(引用類型內(nèi)部屬性可修改)
console.log(user.name); // 輸出 趙六
?? 2. 變量提升(Hoisting)
React 組件本質(zhì)就是 JavaScript 函數(shù)。但如果不理解變量提升,你常會遇到 “變量還沒使用就報錯” 的困惑 —— 這其實是提升機制在背后起作用。
示例:變量提升的表現(xiàn)與注意點
// 函數(shù)聲明會整體提升,可在聲明前調(diào)用
sayHello(); // 輸出 Hello!
function sayHello() {
console.log("Hello!");
}
// var聲明的變量僅提升“聲明”,不提升“賦值”
console.log(num); // 輸出 undefined(聲明提升,賦值未提升)
var num = 10;
console.log(num); // 輸出 10
// let/const 無變量提升,存在暫時性死區(qū)
console.log(str); // 報錯(無法訪問未初始化的let變量)
let str = "test";
?? 3. 閉包(Closures)
閉包不只是面試題考點 —— 它是 React Hooks(尤其是useState、useEffect)和事件處理的核心動力。沒有閉包,React 的狀態(tài)保存與行為邏輯幾乎無法實現(xiàn)。
示例:閉包在 React 中的實際應(yīng)用
// 閉包基礎(chǔ):內(nèi)部函數(shù)訪問外部函數(shù)變量,變量不會被銷毀
function createCounter() {
let count = 0; // 外部函數(shù)變量,被內(nèi)部函數(shù)引用
return function () {
count++;
return count;
};
}
const counter = createCounter();
console.log(counter()); // 輸出 1
console.log(counter()); // 輸出 2(count狀態(tài)被保留)
// React中閉包的典型場景:useState依賴閉包保存狀態(tài)
import { useState } from "react";
function CounterComponent() {
const [count, setCount] = useState(0);
// 事件處理函數(shù)通過閉包訪問count狀態(tài)
const handleIncrement = () => {
setCount(count + 1); // 此處能訪問count,正是閉包的作用
};
return <button onclick="{handleIncrement}">計數(shù):{count}</button>;
}
?? 4. 回調(diào)函數(shù)(Callback Functions)
React 嚴(yán)重依賴回調(diào)函數(shù) —— 從事件處理(onClick)到副作用管理(useEffect)都離不開它。掌握 “如何傳遞函數(shù)”“如何延遲執(zhí)行” 以及 “如何避免回調(diào)地獄”,是 React 開發(fā)的基礎(chǔ)。
示例:React 中的回調(diào)函數(shù)與優(yōu)化
// 1. 事件處理中的回調(diào)函數(shù)
function Button() {
// 回調(diào)函數(shù):點擊時才執(zhí)行
const handleClick = () => {
console.log("按鈕被點擊");
};
// onClick接收回調(diào)函數(shù),不立即執(zhí)行
return <button onclick="{handleClick}">點擊我</button>;
}
// 2. 避免回調(diào)地獄:用async/await優(yōu)化異步請求
async function getUserOrders() {
try {
// 第一步:獲取用戶信息
const userRes = await fetch("/api/user");
const user = await userRes.json();
// 第二步:獲取用戶訂單(無需嵌套)
const ordersRes = await fetch(`/api/user/${user.id}/orders`);
const orders = await ordersRes.json();
console.log("用戶訂單:", orders);
} catch (error) {
console.error("請求失敗:", error);
}
}
?? 5. Promise 與 Async/Await
在 React 中,調(diào)用 API 獲取數(shù)據(jù)是日常操作(如用fetch或國內(nèi)常用的axios)。掌握 Promise 與 async/await,能讓你寫出不阻塞瀏覽器的異步代碼,避免頁面 “卡死”。
示例:結(jié)合 axios 的異步數(shù)據(jù)請求(國內(nèi)常用場景)
import { useState, useEffect } from "react";
import axios from "axios"; // 國內(nèi)常用的HTTP庫
function DataComponent() {
const [userData, setUserData] = useState(null);
const [loading, setLoading] = useState(false);
// 用async/await封裝異步請求
const fetchUserData = async () => {
setLoading(true);
try {
// 示例:請求掘金用戶接口(需處理跨域,實際項目需后端代理)
const res = await axios.get("https://api.juejin.cn/user_api/v1/user/get");
setUserData(res.data.data); // 賦值返回的用戶數(shù)據(jù)
} catch (error) {
console.error("數(shù)據(jù)獲取失敗:", error);
} finally {
setLoading(false); // 無論成功失敗,都結(jié)束加載狀態(tài)
}
};
// 組件掛載時執(zhí)行請求
useEffect(() => {
fetchUserData();
}, []);
// 加載狀態(tài)與數(shù)據(jù)展示
return loading ? (
<div>加載中...</div>
) : (
<div>歡迎,{userData?.user_name || "游客"}</div>
);
}
?? 6. 數(shù)組方法(map、filter、reduce)
React 開發(fā)圍繞數(shù)組展開:用map渲染列表、用filter篩選數(shù)據(jù)、用reduce統(tǒng)計信息 —— 這些方法能讓你的 UI 邏輯更簡潔高效。
示例:React 中數(shù)組方法的高頻用法
import { useState } from "react";
function UserList() {
const [users, setUsers] = useState([
{ id: 1, name: "張三", age: 16, isVip: false },
{ id: 2, name: "李四", age: 20, isVip: true },
{ id: 3, name: "王五", age: 22, isVip: true },
]);
// 1. map:渲染列表(React必用,需加key)
const userItems = users.map((user) => (
<li key="{user.id}">
{user.name}({user.age}歲){user.isVip ? "[VIP]" : ""}
</li>
));
// 2. filter:篩選VIP用戶
const vipUsers = users.filter((user) => user.isVip);
// 3. reduce:計算用戶平均年齡
const avgAge = users.reduce((sum, user) => sum + user.age, 0) / users.length;
return (
<div>
<h3>所有用戶</h3>
<ul>{userItems}</ul>
<p>VIP用戶數(shù):{vipUsers.length}</p>
<p>平均年齡:{avgAge.toFixed(1)}</p>
</div>
);
}
?? 7. 解構(gòu)(Destructuring)
在 React 中,從props或state中提取值時,解構(gòu)能讓代碼更簡潔易讀 —— 尤其在函數(shù)組件中,幾乎是 “標(biāo)配” 寫法。
示例:React 中的解構(gòu)應(yīng)用
// 1. 解構(gòu)props(最常用場景)
// 未解構(gòu):代碼冗長
function Greeting(props) {
return <h1>你好,{props.name}!年齡:{props.age}</h1>;
}
// 解構(gòu):簡潔清晰
function Greeting({ name, age }) {
return <h1>你好,{name}!年齡:{age}</h1>;
}
// 2. 解構(gòu)state
import { useState } from "react";
function Profile() {
const [user, setUser] = useState({
name: "張三",
address: "北京",
phone: "138****1234",
});
// 從user中解構(gòu)需要的屬性
const { name, address } = user;
return <div>{name} 住在 {address}</div>;
}
// 3. 數(shù)組解構(gòu)(配合useState)
const [count, setCount] = useState(0); // 解構(gòu)useState返回的數(shù)組
?? 8. 擴展與剩余運算符(Spread & Rest Operators)
這兩個運算符在 React 中高頻出現(xiàn):處理props傳遞、更新狀態(tài)、合并對象等場景都能用到,極大簡化了數(shù)據(jù)操作邏輯。
示例:React 中的運算符應(yīng)用
// 1. 擴展運算符(...):傳遞所有props
function Parent() {
const user = { name: "張三", age: 25, gender: "男" };
// 用...將user的所有屬性傳遞給Child,無需逐個寫props
return <child {...user} />;
}
function Child({ name, age, gender }) {
return <div>{name},{age}歲,{gender}</div>;
}
// 2. 擴展運算符:更新React狀態(tài)(不可直接修改原狀態(tài))
import { useState } from "react";
function Profile() {
const [profile, setProfile] = useState({
name: "張三",
age: 25,
});
// 只更新age,保留其他屬性(正確寫法)
const updateAge = () => {
setProfile({ ...profile, age: 26 }); // ...profile復(fù)制原有屬性
};
return (
<div>
<p>年齡:{profile.age}</p>
<button onclick="{updateAge}">增加年齡</button>
</div>
);
}
// 3. 剩余運算符(...):收集多個參數(shù)
function sum(...numbers) {
// numbers是一個數(shù)組,包含所有傳入的參數(shù)
return numbers.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3)); // 輸出 6
?? 9. 真值與假值(Truthy and Falsy Values)
React 的條件渲染完全依賴 JavaScript 的真值 / 假值判斷。理解 “哪些值被視為 true,哪些被視為 false”,能幫你避免 UI 渲染異常(如空數(shù)組顯示 “有數(shù)據(jù)”)。
示例:條件渲染中的真值 / 假值應(yīng)用
// JavaScript中的假值(僅6個):false、0、""、null、undefined、NaN
// 其他值均為真值(包括 "0"、{}、[]、true 等)
import { useState } from "react";
function LoginStatus() {
const [user, setUser] = useState(null); // 未登錄時為null(假值)
// 條件1:用戶登錄(user為真值)顯示歡迎語
// 條件2:用戶未登錄(user為假值)顯示登錄按鈕
return user ? (
<div>歡迎,{user.name}!</div>
) : (
<button onclick="{()" => setUser({ name: "張三" })}>登錄</button>
);
}
// 注意:空數(shù)組[]是真值,需判斷長度
function List({ data }) {
// 錯誤:data為[]時,if(data)為true,會顯示“有數(shù)據(jù)”
// if (data) return <div>有數(shù)據(jù)</div>;
// 正確:判斷數(shù)組長度
if (data.length > 0) {
return <div>有數(shù)據(jù):{data.map(item => <p key="{item.id}">{item.name}</p>)}</div>;
}
return <div>無數(shù)據(jù)</div>;
}
?? 10. DOM 與事件(基礎(chǔ))
React 雖然封裝了 DOM(虛擬 DOM),但仍需與原生 DOM 交互。理解基礎(chǔ)的 DOM 操作和原生事件,能幫你搞懂 React 合成事件的底層邏輯,避免 “事件綁定失效” 等問題。
示例:原生 DOM 與 React 合成事件對比
// 1. 原生DOM操作(理解原理)
// HTML:<button id="nativeBtn">原生按鈕</button>
const nativeBtn = document.getElementById("nativeBtn");
nativeBtn.addEventListener("click", () => {
console.log("原生按鈕被點擊");
});
// 2. React合成事件(開發(fā)常用)
import { useState } from "react";
function ReactButton() {
const [count, setCount] = useState(0);
// React合成事件:onClick(駝峰命名,區(qū)別于原生onclick)
const handleClick = (e) => {
setCount(count + 1);
// e是React合成事件對象,可通過e.nativeEvent獲取原生事件
console.log("原生事件對象:", e.nativeEvent);
};
// React自動管理事件解綁,無需手動移除
return <button onclick="{handleClick}">點擊次數(shù):{count}</button>;
}
// 3. 阻止默認(rèn)行為(如表單提交)
function Form() {
const handleSubmit = (e) => {
// 阻止表單默認(rèn)提交(原生與React寫法一致)
e.preventDefault();
console.log("表單已處理,不刷新頁面");
};
return (
<form onSubmit="{handleSubmit}">
<button type="submit">提交表單</button>
</form>
);
}
?? 為什么這些概念如此重要?
理論上,即使不掌握這些概念,你也能 “拼湊” 出一個 React 應(yīng)用 —— 但代價是:頻繁困惑、卡殼,只能從 Stack Overflow(或國內(nèi)的掘金、CSDN)復(fù)制代碼,卻不懂背后的邏輯。
這些概念是 React 開發(fā)的 “地基”:它們不僅幫你寫出代碼,更能讓你理解 “React 為什么要這么設(shè)計”(比如 Hooks 依賴閉包、狀態(tài)不可直接修改)。
?? 加餐:視頻學(xué)習(xí)資源
如果你偏好 “視覺 + 場景化” 學(xué)習(xí),不必局限于國外平臺(如 YouTube)。國內(nèi)的技術(shù)平臺(如 B 站、掘金視頻)有大量優(yōu)質(zhì)教程,搜索 “React 前置 JS 知識點”“React 基礎(chǔ) JS 概念”,就能找到適合國內(nèi)開發(fā)者的入門內(nèi)容,幫你更清晰地建立知識體系。
? 最后想說的話
掌握 React,不只是學(xué)習(xí)一個新庫 —— 更是深化 JavaScript 基礎(chǔ)的過程。在急于學(xué)習(xí) JSX、Hooks 或路由之前,先夯實這些核心概念,你會發(fā)現(xiàn)后續(xù)的 React 學(xué)習(xí)會 “順理成章”,而不是 “死記硬背”。
祝大家編碼愉快!??
浙公網(wǎng)安備 33010602011771號