默认只显示问题 —— 先自己在心里答一遍,再展开对答案。答不上来就标「不会」,下次抽认卡会先抽它。Only the question shows by default. Answer it in your head first, then open the answer. Mark the ones you miss; the flashcard round puts those first.
正在读这台浏览器里的标记…Reading your marks from this browser…
标记不是打分,是给下一轮排队Marks are a queue, not a score
标「不会」的题会排到抽认卡最前面,标「会」的进低频池排最后。所以别客气 —— 觉得答得磕磕巴巴就标「模糊」。准备好了就去抽认卡。“No idea” jumps to the front of the next round; “got it” drops to the back. So be honest — if it came out shaky, mark it shaky. Then go run a flashcard round.
找一道题Find one按方向、掌握状态筛Filter by topic and markReact 与生态React & ecosystem
In one line: a single-page application — one HTML document gets loaded, and from then on JS swaps the content on the client instead of asking the server for a whole new page.
Upsides: no white flash when you change pages, it feels close to a native app, and front end and back end are fully separated (the server only returns JSON).
Costs — this is the half they probe:
Slow first paint — you have to download and run a big JS bundle before anything shows up. The fixes are code splitting (React.lazy, see #347) and SSR.
Weak SEO — a crawler receives an empty<div id="root"></div>. The fix is SSR / SSG (Next.js).
You own the routing — back and forward, deep links, staying on the current page after a refresh, all of it rides on the history API plus a fallback on the server. “404 on refresh” means the fallback is missing.
Memory leaks — the page never reloads, so timers and listeners are never cleared for you. That is the practical reason useEffect needs a cleanup function.
Follow-up: “When is an MPA better?” — content sites (blogs, docs, product detail pages) where SEO and first paint matter and the interaction stays simple. “It depends on the case” beats praising SPAs unconditionally.
In one line:declarative + component-based + one-way data flow — you describe what the UI should look like and React makes the DOM match.
Declarative — you write {items.map(...)}, not “find the ul, create an li, appendChild”. What you drop is the step-by-step code for getting from state A to state B, and that is where most bugs live.
Components — the UI splits into reusable units you can test on their own.
One-way data flow — props go down, events go up. When something breaks, there is exactly one path to trace: the data can only have come from one direction.
Ecosystem — Router, state libraries, Next.js, React Native (the same mental model gets you a mobile app).
They will ask for the downsides (have them ready): it is only a view library, so you pick the router and the state layer yourself — the cost of those decisions is real; performance work is manual (memo / useMemo; there was no automatic memoization before React 19); JSX and the hook rules are a hurdle for beginners; and version migrations carry a lot of mental load (class → hooks → Server Components).
In one line: React is a library (it handles the view, you choose the rest); Angular is a framework (routing, HTTP, forms, dependency injection and testing all come in the box).
React
Angular
What it is
A library
A full framework
Language
JS / TS, JSX
TypeScript required, HTML templates
Data flow
One-way
Two-way binding available (ngModel)
DOM strategy
Virtual DOM
Incremental DOM + change detection
Learning curve
Easy to start, but many choices to make
Steep at first (DI, RxJS, decorators), consistent after
Fits
Flexible work, fast iteration, a team happy to assemble its own stack
Large enterprise projects that need one standard
How to answer without picking a fight: do not talk one down to lift the other. Say “React gives you freedom and the burden of choosing; Angular gives you conventions and a learning cost. The answer differs for a small fast project and for a big one many people maintain for years.”
They will ask about Vue — Vue sits between the two: it has an official router and state library (more unified than React) but stays lighter than Angular, and the template syntax is quick to pick up.
In one line: a syntax extension for JavaScript that lets you write HTML-like structure inside JS. The browser does not understand it — Babel compiles it into plain function calls.
What it compiles to (this is the part being tested): old versions produced React.createElement(type, props, ...children); since React 17 the new JSX transform emits _jsx(...), which is why you no longer have to write import React by hand.
The rules you should state clearly:
One root node is required — a function can only return one value. If you do not want another div, use a Fragment (see #338).
Attribute names are camelCase — className (because class is a JS keyword), htmlFor, onClick.
{} holds an expression, not a statement — so conditional rendering uses a ternary or &&, never if.
JSX escapes by default, so you get XSS protection for free; injecting raw HTML takes an explicit dangerouslySetInnerHTML — the name is deliberately ugly so that you stop and think.
Follow-up: “Is JSX mandatory?” — no, you can call createElement yourself, nobody wants to. The value of JSX is that UI structure looks like structure in the code.
一句话:虚拟 DOM 是用普通 JS 对象描述真实 DOM 的一棵轻量树。 状态变了先在内存里生成新树, 和旧树 diff,算出最小改动,再一次性打到真实 DOM 上。
为什么快 —— 说准这两条:
批量—— 十次 state 更新 合并成一次 DOM 操作, 避免十次重排(见 #288)。
最小化—— 只改真正变了的属性和节点, 不重建整棵子树。
但要说出这层真相(加分点):虚拟 DOM 不一定比手写 DOM 快—— 精心手写的原生操作永远更快, 虚拟 DOM 还额外付出了「建树 + diff」的开销。它真正的价值是「在保持声明式写法的同时, 性能仍然够好」—— 是可维护性和性能的折中, 不是性能银弹。
diff 的三条启发式规则(把 O(n³) 降到 O(n) 的关键):
只比同层,不跨层移动节点。 跨层的话就是删了重建。
类型不同直接整棵重建——div 换成 span, 子树全部丢弃重做(state 也丢)。
同层列表用 key 认身份。
key 为什么不能用 index—— 这是 React 面试最实用的一条: 在开头插入或删除一项时, 所有元素的 index 都变了, React 会认为「每一项的内容都变了」, 于是大量误更新; 更糟的是非受控输入框的内容会串到别的行, 因为 DOM 节点被复用了。Q1 那道真题里删除笔记的 bug 就是这个。
In one line: the virtual DOM is a lightweight tree of plain JS objects describing the real DOM. When state changes, React builds a new tree in memory, diffs it against the old one, works out the smallest set of changes, and applies them to the real DOM in one go.
Why it is fast — get these two right:
Batching — ten state updates collapse into one DOM write, so you avoid ten reflows (see #288).
Minimising — only the attributes and nodes that really changed get touched; whole subtrees are not rebuilt.
But say this part too — it is the bonus point:the virtual DOM is not necessarily faster than hand-written DOM code — carefully tuned native operations always win, and the virtual DOM pays extra for building a tree and diffing it. Its real value is that you keep the declarative style and performance is still good enough — it is a trade-off between maintainability and performance. It is not the right choice everywhere.
The three diff heuristics (what turns O(n³) into O(n)):
Compare the same level only; nodes never move across levels. Crossing a level means delete and rebuild.
A different type rebuilds the whole subtree — swap a div for a span and the subtree is thrown away and redone, state included.
Lists on the same level use key for identity.
Why index must not be the key — the most useful thing you can say in a React interview: insert or delete at the front and every index shifts, so React believes the content of every row changed and does a pile of needless updates; worse, text typed into an uncontrolled input ends up on the wrong row, because the DOM node got reused. The delete-a-note bug in the real Q1 question is exactly this.
4// ✗ index as key: insert one at the front and every key changes
5{todos.map((t,i)=><Rowkey={i}todo={t}/>)}
6
7// ✓ a stable id from the data
8{todos.map((t)=><Rowkey={t.id}todo={t}/>)}
只有「列表永不重排、不增删中间项」时 index 才安全。既然多数列表都会变,直接养成用 id 的习惯。An index is only safe when the list is never reordered and no item is inserted or removed in the middle. Most lists do change, so make using an id your default habit.
In one line: reconciliation is the whole process of comparing the new and old virtual DOM trees and deciding which operations to run on the real DOM. The diff algorithm is one part of it.
How do diff and reconciliation relate? That is the point of the question: diff is the algorithm for how to compare; reconciliation is the full compare, decide and commit flow. Calling them the same thing is not wrong, but telling them apart is better.
The Fiber architecture, from React 16 on, splits the process into two phases — answer this every time:
Render phase (interruptible) — build the Fiber tree, diff, mark what has to change. This phase can be paused and resumed, which is how a high-priority update such as typing jumps the queue.
Commit phase (not interruptible) — apply the marked changes to the real DOM in one pass, then run useEffect. This part must finish synchronously, otherwise users would see a half-rendered screen.
Why does it need to be interruptible? Because the old Stack Reconciler was recursive and could not stop once it started, so a large list update blocked the main thread for tens of milliseconds and typing stuttered. Fiber replaces recursion with a linked list plus a loop, and after each small chunk it checks whether something more urgent came in. This is the foundation of the concurrent features (see #344).
Follow-up: “Why does StrictMode render twice?” — because the render phase can be interrupted and re-run, so the render function has to be pure; the double render is there to expose the impure parts (see #332).
The split in one line:Babel translates (JSX and new syntax → JS the browser understands); Webpack bundles (a pile of modules and assets become the few files you ship).
Babel — @babel/preset-react handles JSX, @babel/preset-env down-levels ES2020+ for your target browsers. It only transforms syntax; new APIs (Promise, Array.flat) still need a polyfill. Drawing that line scores points.
Webpack — reads your imports to build a dependency graph, lets you import CSS and images too, does tree shaking and code splitting, and gives you a dev server with hot reload while you work.
The order: when Webpack hits a .jsx file it calls babel-loader, so Babel is one stage of the Webpack pipeline.
Follow-up: “Are they still used?” — knowing the current state is what shows you keep up: new projects mostly reach for Vite (native ESM plus esbuild in development, Rollup for production), and Babel is often replaced by esbuild or SWC — an order of magnitude faster. Webpack is still everywhere in existing codebases and wherever heavy customisation is needed. The React source project in this course uses Vite — which is why there is no webpack in its node_modules at all.
99 道来自面试题库 #269–#387;TypeScript 深度那 6 道是 DrillLab 自出的(senior 补强,卡片上有标注)。答案都是 DrillLab 写的,所以讲解里的代码块一律标「示意」。每道题都能点回它出处的那一节课。99 questions come from the interview bank (#269–#387); the 6 TypeScript deep-dive ones are DrillLab-made (marked on the card). All answers are written by DrillLab, so every code block here is labelled “demo”. Each card links back to the lesson it came from.