# 前端学习提升代码示例

每题先看《答案清单.md》的约束，再看这里的参考实现和结果。代码按题目所述场景给出；DOM、React、Vue、Next.js 和网络示例需在相应环境运行。题面不完整时，结果只针对代码中明确的输入。

### 01.01
```js
function all(items) {
  return new Promise((resolve, reject) => {
    const values = Array.from(items), out = Array(values.length);
    if (!values.length) return resolve([]);
    let left = values.length;
    values.forEach((value, i) => Promise.resolve(value).then(
      result => { out[i] = result; if (--left === 0) resolve(out); }, reject));
  });
}
all([Promise.resolve(1), 2]).then(console.log);
```
结果：输出 `[1, 2]`；拒绝时返回首个拒绝原因。

### 01.02
```js
function json2dom(node) {
  if (typeof node === 'string' || typeof node === 'number') return document.createTextNode(String(node));
  const el = document.createElement(node.type);
  for (const [key, value] of Object.entries(node.props ?? {})) {
    if (key === 'className') el.className = value;
    else if (key.startsWith('on') && typeof value === 'function') el.addEventListener(key.slice(2).toLowerCase(), value);
    else el.setAttribute(key, String(value));
  }
  for (const child of node.children ?? []) el.append(json2dom(child));
  return el;
}
document.body.append(json2dom({type:'p', children:['Hello']}));
```
结果：页面新增 `<p>Hello</p>`；这里只实现首次创建 DOM。

### 01.03
```js
function flattenTree(nodes, parentId = null, seen = new WeakSet()) {
  return nodes.flatMap(node => {
    if (seen.has(node)) throw Error('cycle');
    seen.add(node);
    const {children = [], ...rest} = node;
    const out = [{...rest, parentId}, ...flattenTree(children, node.id, seen)];
    seen.delete(node);
    return out;
  });
}
console.log(flattenTree([{id:1, children:[{id:2}]}]));
```
结果：`[{id:1,parentId:null},{id:2,parentId:1}]`；循环引用会抛错。

### 01.04
```js
function toTree(rows) {
  const nodes = new Map(rows.map(({id, ...rest}) => [id, {id, ...rest, children:[]}]));
  const roots = [];
  for (const row of rows) {
    const node = nodes.get(row.id);
    if (row.parentId == null) roots.push(node);
    else if (nodes.has(row.parentId)) nodes.get(row.parentId).children.push(node);
    else throw Error(`missing parent ${row.parentId}`);
  }
  return roots;
}
console.log(toTree([{id:1,parentId:null},{id:2,parentId:1}]));
```
结果：根节点 1 的 `children` 包含节点 2；重复 id、环应另行拒绝。

### 01.05
```js
function flat(input, depth = 1) {
  const out = [];
  function visit(arr, left) {
    for (let i = 0; i < arr.length; i++) if (i in arr) {
      if (Array.isArray(arr[i]) && left > 0) visit(arr[i], left - 1);
      else out.push(arr[i]);
    }
  }
  visit(input, depth);
  return out;
}
console.log(flat([1,[2,[3]]], 1));
```
结果：`[1, 2, [3]]`。

### 01.06
```js
function myInstanceof(value, rhs) {
  if (rhs == null) throw TypeError('invalid right operand');
  const method = rhs[Symbol.hasInstance];
  if (method != null) {
    if (typeof method !== 'function') throw TypeError('@@hasInstance must be callable');
    return !!method.call(rhs, value);
  }
  if (typeof rhs !== 'function') throw TypeError('right operand is not callable');
  const prototype = rhs.prototype;
  if (Object(prototype) !== prototype) throw TypeError('invalid prototype');
  if (value === null || (typeof value !== 'object' && typeof value !== 'function')) return false;
  for (let p = Object.getPrototypeOf(value); p; p = Object.getPrototypeOf(p)) if (p === prototype) return true;
  return false;
}
console.log(myInstanceof([], Array), myInstanceof(3, {[Symbol.hasInstance]: x => x === 3}));
```
结果：`true true`；无自定义 `Symbol.hasInstance` 时，基本值返回 `false`。

### 01.07
```js
function callWith(fn, thisArg, ...args) { return Reflect.apply(fn, thisArg, args); }
function applyWith(fn, thisArg, args) { return Reflect.apply(fn, thisArg, args ?? []); }
function bindWith(fn, thisArg, ...bound) {
  return function boundFn(...rest) {
    return new.target ? Reflect.construct(fn, [...bound,...rest], fn) : Reflect.apply(fn, thisArg, [...bound,...rest]);
  };
}
const add=function(x){return this.n+x;};
console.log(callWith(add,{n:2},3),applyWith(add,{n:2},[3]),bindWith(add,{n:2})(3));
```
结果：`5 5 5`；以 `Reflect.apply/construct` 为底层原语，未覆盖原生 bound 函数的全部元数据。

### 01.08
```js
function mapLike(array, callback, thisArg) {
  if (typeof callback !== 'function') throw TypeError('callback');
  const source = Object(array), out = new Array(source.length >>> 0);
  for (let i = 0; i < out.length; i++) if (i in source) out[i] = callback.call(thisArg, source[i], i, source);
  return out;
}
console.log(mapLike([1,,3], x => x * 2));
```
结果：`[2, <空位>, 6]`。

### 01.09
```js
function template(text, data) {
  return text.replace(/\{\{\s*([\w.]+)\s*\}\}/g, (_, path) =>
    String(path.split('.').reduce((obj, key) => obj?.[key], data) ?? ''));
}
console.log(template('Hi {{user.name}}', {user:{name:'Ada'}}));
```
结果：`Hi Ada`；若写入 HTML，必须按 HTML 上下文转义。

### 01.10
```js
function get(object, path, fallback) {
  const keys = Array.isArray(path) ? path : String(path).replace(/\[(\d+)\]/g, '.$1').split('.');
  const value = keys.reduce((current, key) => current?.[key], object);
  return value === undefined ? fallback : value;
}
console.log(get({a:[{b:0}]}, 'a[0].b', 9));
```
结果：`0`；复杂 Lodash 路径语法不在这个简化版中。

### 01.11
```js
function clone(value, seen = new WeakMap()) {
  if (value === null || typeof value !== 'object') return value;
  if (seen.has(value)) return seen.get(value);
  if (value instanceof Date) return new Date(value);
  if (value instanceof RegExp) return new RegExp(value.source, value.flags);
  const out = Array.isArray(value) ? [] : Object.create(Object.getPrototypeOf(value));
  seen.set(value, out);
  for (const key of Reflect.ownKeys(value)) out[key] = clone(value[key], seen);
  return out;
}
const a = {}; a.self = a; const b = clone(a); console.log(b !== a, b.self === b);
```
结果：`true true`；Map/Set 等需专门处理。

### 01.12
```js
function Parent(name) { this.name = name; }
Parent.prototype.greet = function() { return `Hi ${this.name}`; };
function Child(name) { Parent.call(this, name); }
Child.prototype = Object.create(Parent.prototype, {constructor:{value:Child, writable:true, configurable:true}});
console.log(new Child('Ada').greet());
```
结果：`Hi Ada`；父构造函数每个实例只执行一次。

### 01.13
```js
function emitter() {
  const events = new Map();
  return {
    on(name, fn) { const set = events.get(name) ?? new Set(); set.add(fn); events.set(name,set); return () => set.delete(fn); },
    emit(name, ...args) { for (const fn of [...(events.get(name) ?? [])]) fn(...args); }
  };
}
const bus = emitter(); const off = bus.on('x', console.log); bus.emit('x', 1); off();
```
结果：输出 `1` 一次；取消订阅后不再输出。

### 02.01
```js
class APromise {
  #state='pending'; #value; #listeners=[];
  constructor(executor) {
    let sealed=false;
    const settle=(state,value)=>{
      if(this.#state!=='pending')return;
      this.#state=state;this.#value=value;
      for(const listener of this.#listeners)queueMicrotask(listener);
      this.#listeners=[];
    };
    const resolve=value=>{if(sealed)return;sealed=true;resolvePromise(this,value,x=>settle('fulfilled',x),e=>settle('rejected',e));};
    const reject=error=>{if(sealed)return;sealed=true;settle('rejected',error);};
    try{executor(resolve,reject);}catch(error){reject(error);}
  }
  then(onFulfilled,onRejected){
    let next;
    next=new APromise((resolve,reject)=>{
      const run=()=>{
        try{
          const fulfilled=this.#state==='fulfilled';
          const handler=fulfilled?onFulfilled:onRejected;
          if(typeof handler!=='function')return fulfilled?resolve(this.#value):reject(this.#value);
          resolvePromise(next,handler(this.#value),resolve,reject);
        }catch(error){reject(error);}
      };
      this.#state==='pending'?this.#listeners.push(run):queueMicrotask(run);
    });
    return next;
  }
}
function resolvePromise(promise,value,resolve,reject){
  if(value===promise)return reject(new TypeError('self resolution'));
  if(value!==null && (typeof value==='object'||typeof value==='function')){
    let then;try{then=value.then;}catch(error){return reject(error);}
    if(typeof then==='function'){
      let called=false;
      try{then.call(value,y=>{if(!called){called=true;resolvePromise(promise,y,resolve,reject);}},e=>{if(!called){called=true;reject(e);}});}
      catch(error){if(!called)reject(error);}
      return;
    }
  }
  resolve(value);
}
new APromise(resolve=>resolve({then(ok){ok(3);ok(4);}})).then(console.log);
```
结果：只输出 `3`；包含状态、异步 `then`、链式返回、thenable 吸收和自解析拒绝，尚未运行官方 Promises/A+ 测试套件。

### 02.02
```js
function finallyLike(promise, onFinally) {
  if (typeof onFinally !== 'function') return promise.then(onFinally, onFinally);
  return promise.then(
    value => Promise.resolve(onFinally()).then(() => value),
    error => Promise.resolve(onFinally()).then(() => { throw error; })
  );
}
finallyLike(Promise.resolve(3), () => console.log('cleanup')).then(console.log);
```
结果：先输出 `cleanup`，再输出 `3`；子类 species 语义未覆盖。

### 02.03
```js
function allSettled(items) {
  return Promise.all(Array.from(items, item => Promise.resolve(item).then(
    value => ({status:'fulfilled', value}), reason => ({status:'rejected', reason}))));
}
allSettled([1, Promise.reject('x')]).then(console.log);
```
结果：`[{status:'fulfilled',value:1},{status:'rejected',reason:'x'}]`。

### 02.04
```js
function race(items) {
  return new Promise((resolve, reject) => {
    for (const item of items) Promise.resolve(item).then(resolve, reject);
  });
}
race([Promise.resolve('first'), new Promise(r => setTimeout(r, 10, 'later'))]).then(console.log);
```
结果：`first`；空输入永不落定。

### 02.05
```js
function catchLike(promise, onRejected) { return promise.then(undefined, onRejected); }
catchLike(Promise.reject('error'), e => `handled ${e}`).then(console.log);
```
结果：`handled error`。

### 02.06
```js
function resolveLike(value) { return new Promise(resolve => resolve(value)); }
resolveLike({then(resolve){resolve(3)}}).then(console.log);
```
结果：`3`；原生 Promise 的 resolve 过程会吸收 thenable。

### 02.07
```js
function rejectLike(reason) { return new Promise((_, reject) => reject(reason)); }
rejectLike('bad').catch(console.log);
```
结果：`bad`；传入 Promise 时不会吸收其状态。

### 03.01
```js
const sleep = ms => new Promise(r => setTimeout(r, ms));
async function traffic(signal) {
  for (const [color, ms] of [['red',3000],['green',2000],['yellow',1000]]) {
    if (signal.aborted) return;
    console.log(color); await sleep(ms);
  }
}
traffic(new AbortController().signal);
```
结果：依次打印 `red`、`green`、`yellow`；示例只跑一轮，取消需同时清理正在等待的定时器。

### 03.02
```js
async function request(url, options = {}) {
  const response = await fetch(url, options);
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
  return response.json();
}
request('/api/user').then(console.log).catch(console.error);
```
结果：2xx JSON 响应解析为对象；HTTP 错误进入 `catch`。

### 03.03
```js
async function repeat(fn, count, interval) {
  for (let i = 0; i < count; i++) {
    await new Promise(r => setTimeout(r, interval));
    fn(i + 1);
  }
}
repeat(console.log, 5, 1000);
```
结果：约每秒输出 `1` 到 `5`，首次输出在约 1 秒后。

### 03.04
```js
function withTimeout(promise, ms = 1000) {
  let timer;
  return Promise.race([promise, new Promise((_, reject) => {
    timer = setTimeout(() => reject(new Error('timeout')), ms);
  })]).finally(() => clearTimeout(timer));
}
withTimeout(Promise.resolve(3)).then(console.log);
```
结果：输出 `3`；超时只终止等待，不取消原异步工作。

### 03.05
```js
async function fetchWithin5s(url) {
  const controller = new AbortController();
  const timer = setTimeout(() => controller.abort(), 5000);
  try { return await fetch(url, {signal:controller.signal}); }
  finally { clearTimeout(timer); }
}
```
结果：5 秒未完成会取消 `fetch` 并以 AbortError 拒绝。

### 03.06
```js
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
sleep(10).then(() => console.log('done'));
```
结果：约 10 毫秒后输出 `done`。

### 03.07
```js
async function printOneToFive() {
  for (let i = 1; i <= 5; i++) {
    await new Promise(r => setTimeout(r, 1000)); console.log(i);
  }
}
printOneToFive();
```
结果：每隔约 1 秒依次输出 `1,2,3,4,5`。

### 03.08
```js
function intervalByTimeout(fn, ms) {
  let stopped = false, id;
  function tick() { if (stopped) return; fn(); id = setTimeout(tick, ms); }
  id = setTimeout(tick, ms);
  return () => { stopped = true; clearTimeout(id); };
}
const stop = intervalByTimeout(() => console.log('tick'), 1000);
setTimeout(stop, 3100);
```
结果：约输出三次 `tick` 后停止。

### 03.09
```js
function loadImage(url) {
  return new Promise((resolve, reject) => {
    const image = new Image();
    image.onload = () => resolve(image);
    image.onerror = () => reject(new Error('image load failed'));
    image.src = url;
  });
}
loadImage('/logo.png').then(img => console.log(img.naturalWidth));
```
结果：成功时输出图片自然宽度；失败时 Promise 拒绝。

### 03.10
```js
function ajax(url) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url);
    xhr.onload = () => xhr.status >= 200 && xhr.status < 300 ? resolve(xhr.responseText) : reject(new Error(`HTTP ${xhr.status}`));
    xhr.onerror = () => reject(new Error('network error'));
    xhr.send();
  });
}
ajax('/api').then(console.log).catch(console.error);
```
结果：成功返回响应文本，网络错误或非 2xx 拒绝。

### 03.11
```js
function timeoutByInterval(fn, ms) {
  const id = setInterval(() => { clearInterval(id); fn(); }, ms);
  return () => clearInterval(id);
}
timeoutByInterval(() => console.log('once'), 1000);
```
结果：约 1 秒后仅输出一次 `once`。

### 03.12
```js
async function serial(urls) {
  const out = [];
  for (const url of urls) {
    const response = await fetch(url);
    if (!response.ok) throw Error(`HTTP ${response.status}`);
    out.push(await response.json());
  }
  return out;
}
```
结果：三个 URL 时顺序发三次请求，按请求顺序返回三项结果。

### 03.13
```js
async function timedRequest(url) {
  const response = await fetch(url, {signal:AbortSignal.timeout(3000)});
  if (!response.ok) throw Error(`HTTP ${response.status}`);
  return response.json();
}
```
结果：超过 3 秒会超时拒绝；2xx JSON 返回解析值。

### 03.14
```js
const controller = new AbortController();
const request = fetch('/api/slow', {signal:controller.signal});
controller.abort();
request.catch(error => console.log(error.name));
```
结果：输出 `AbortError`；取消的是支持 AbortSignal 的请求。

### 03.15
```js
async function fastest(urls) {
  const times = await Promise.all(urls.map(async url => {
    const start = performance.now();
    try { const response = await fetch(url, {cache:'no-store'}); if (!response.ok) throw Error(); await response.arrayBuffer(); return {url, ms:performance.now()-start}; }
    catch { return {url, ms:Infinity}; }
  }));
  return times.reduce((best, item) => item.ms < best.ms ? item : best);
}
```
结果：返回 GET 下载耗时最短的地址；这不等于上传速度。

### 03.16
```js
function accurateInterval(fn, interval) {
  let next = performance.now() + interval, id, stopped = false;
  function tick() { if (stopped) return; fn(); next += interval; id = setTimeout(tick, Math.max(0,next-performance.now())); }
  id = setTimeout(tick, interval);
  return () => { stopped = true; clearTimeout(id); };
}
```
结果：以绝对计划时间补偿单次回调耗时；后台节流仍可能延迟。

### 03.17
```js
const target = performance.now() + 1000;
setTimeout(() => console.log(Math.round(performance.now() - target)), 1000);
```
结果：输出实际漂移毫秒数，通常非严格的 `0`。

### 03.18
```js
async function firstResponse(urls) {
  const controllers = urls.map(() => new AbortController());
  const stopOthers = i => controllers.forEach((c,j) => { if (j !== i) c.abort(); });
  return Promise.race(urls.map((url, i) => fetch(url, {signal:controllers[i].signal}).then(
    response => { stopOthers(i); return response; },
    error => { stopOthers(i); throw error; }
  )));
}
```
结果：返回首个完成的响应；首个失败也会直接拒绝。

### 03.19
```js
async function ordered(urls) {
  const pending = urls.map(url => fetch(url).then(r => r.text()).then(value => ({value}), error => ({error})));
  for (const task of pending) {
    const item = await task;
    if (item.error) throw item.error;
    console.log(item.value);
  }
}
```
结果：请求并发开始，打印顺序与 `urls` 一致。

### 03.20
```js
async function runSerial(tasks) {
  const out = [];
  for (const task of tasks) out.push(await task());
  return out;
}
runSerial([() => Promise.resolve(1), () => Promise.resolve(2)]).then(console.log);
```
结果：输出 `[1,2]`；任务函数在轮到时才启动。

### 03.21
```js
async function limitAll(tasks, limit) {
  if (!Number.isInteger(limit) || limit < 1) throw RangeError('limit');
  const out = Array(tasks.length); let next = 0;
  async function worker() { while (next < tasks.length) { const i = next++; out[i] = await tasks[i](); } }
  await Promise.all(Array.from({length:Math.min(limit,tasks.length)}, worker));
  return out;
}
limitAll([() => Promise.resolve(1), () => Promise.resolve(2)], 10).then(console.log);
```
结果：`[1,2]`；同时运行数不超过 `limit`。

### 03.22
```js
for (const [ms, value] of [[1000,'1'],[3000,'2'],[4000,'3']]) {
  setTimeout(() => console.log(value), ms);
}
```
结果：相对开始时刻约 1、3、4 秒分别输出 `1`、`2`、`3`。

### 03.23
```js
function scheduler(limit) {
  if (!Number.isInteger(limit) || limit < 1) throw RangeError('limit');
  let active = 0; const queue = [];
  function drain() {
    while (active < limit && queue.length) {
      const {task,resolve,reject} = queue.shift(); active++;
      Promise.resolve().then(task).then(resolve,reject).finally(() => { active--; drain(); });
    }
  }
  return task => new Promise((resolve,reject) => { queue.push({task,resolve,reject}); drain(); });
}
const add = scheduler(2); add(() => Promise.resolve(3)).then(console.log);
```
结果：输出 `3`；同时运行的任务最多 2 个。

### 03.24
```js
class Scheduler {
  #queue=[]; #active=0;
  constructor(limit) { if(!Number.isInteger(limit)||limit<1)throw RangeError('limit');this.limit=limit; }
  add(task){return new Promise((resolve,reject)=>{this.#queue.push({task,resolve,reject});this.#drain();});}
  #drain(){while(this.#active<this.limit&&this.#queue.length){const {task,resolve,reject}=this.#queue.shift();this.#active++;Promise.resolve().then(task).then(resolve,reject).finally(()=>{this.#active--;this.#drain();});}}
}
new Scheduler(2).add(() => Promise.resolve('ok')).then(console.log);
```
结果：`ok`；同时运行的任务最多 2 个。

### 03.25
```ts
async function limitAll<T>(tasks: Array<() => Promise<T>>, limit: number): Promise<T[]> {
  if (!Number.isInteger(limit) || limit < 1) throw new RangeError('limit');
  const out = new Array<T>(tasks.length); let next = 0;
  async function worker() { while (next < tasks.length) { const i = next++; out[i] = await tasks[i](); } }
  await Promise.all(Array.from({length:Math.min(limit,tasks.length)}, worker));
  return out;
}
```
结果：最多 `limit` 项并发，返回值按输入顺序组成 `T[]`。

### 03.26
```js
function ignoreWhilePending(request) {
  let busy = false;
  return async (...args) => {
    if (busy) return undefined;
    busy = true;
    try { return await request(...args); }
    finally { busy = false; }
  };
}
```
结果：前次未完成时后续调用直接得到 `undefined`；前次结束后可重新请求。

### 03.27
```js
async function printTime(signal) {
  while (!signal.aborted) {
    await new Promise(r => setTimeout(r, 3000));
    if (!signal.aborted) console.log(new Date().toISOString());
  }
}
```
结果：约每 3 秒输出一次当前时间；示例停止后仍要等当前计时器结束。

### 03.28
```js
const read = file => new Promise((resolve,reject) => require('node:fs').readFile(file,'utf8',(e,data) => e ? reject(e) : resolve(data)));
async function load() { try { return await read('a.txt'); } catch (error) { console.error(error); throw error; } }
```
结果：文件存在时返回文本，失败时记录并抛出错误。

### 03.29
```js
function requestQueue(limit) {
  if(!Number.isInteger(limit)||limit<1)throw RangeError('limit');
  let active=0;const queue=[];
  function drain(){while(active<limit&&queue.length){const {url,resolve,reject}=queue.shift();active++;fetch(url).then(r=>{if(!r.ok)throw Error(`HTTP ${r.status}`);return r.json();}).then(value=>{console.log(value);resolve(value);},reject).finally(()=>{active--;drain();});}}
  return url=>new Promise((resolve,reject)=>{queue.push({url,resolve,reject});drain();});
}
```
结果：同时最多发 `limit` 个请求；每个完成时打印并返回该请求结果。

### 03.30
```js
async function retry(task, attempts, fallback) {
  if (!Number.isInteger(attempts) || attempts < 1) throw RangeError('attempts');
  let last;
  for (let i = 0; i < attempts; i++) {
    try { return await task(); } catch (error) { last = error; }
  }
  if (fallback !== undefined) return fallback;
  throw last;
}
retry(() => Promise.reject('offline'), 2, 'cached').then(console.log);
```
结果：尝试两次后输出 `cached`；每次请求超时需在 `task` 内实现。

### 03.31
```js
function mySetInterVal(fn, a, b) {
  let count = 0, stopped = false, id;
  function tick() { if (stopped) return; fn(); count++; id = setTimeout(tick, a + count*b); }
  id = setTimeout(tick, a);
  return () => { stopped = true; clearTimeout(id); };
}
const myClear = mySetInterVal(() => console.log('tick'), 1000, 500);
```
结果：约在 1、2.5、4.5 秒输出，调用 `myClear()` 停止。

### 04.01
```js
function uniqueRandom(min, max, count) {
  const size = max - min + 1;
  if (!Number.isInteger(size) || !Number.isInteger(count) || count < 0 || count > size) throw RangeError('range/count');
  const pool = Array.from({length:size}, (_,i) => min + i);
  for (let i = 0; i < count; i++) { const j = i + Math.floor(Math.random()*(size-i)); [pool[i],pool[j]] = [pool[j],pool[i]]; }
  return pool.slice(0,count);
}
console.log(uniqueRandom(1,3,3).sort());
```
结果：一定包含 `1,2,3` 各一次；抽取顺序随机。

### 04.02
```js
function run(generator) {
  return new Promise((resolve,reject) => {
    const iterator = generator();
    function step(method, value) {
      let state;
      try { state = iterator[method](value); } catch (error) { reject(error); return; }
      if (state.done) { resolve(state.value); return; }
      Promise.resolve(state.value).then(x => step('next',x), e => step('throw',e));
    }
    step('next');
  });
}
run(function*(){ return (yield Promise.resolve(2)) + 1; }).then(console.log);
```
结果：`3`；展示 async/await 的生成器驱动核心，不等于引擎内部实现。

### 04.03
```js
function sum(n) { return n <= 0 ? 0 : n + sum(n-1); }
console.log(sum(100));
```
结果：`5050`。

### 04.04
```js
const palindromes = Array.from({length:10000}, (_,i) => i+1)
  .filter(n => String(n) === [...String(n)].reverse().join(''));
console.log(palindromes.slice(0,12));
```
结果：前 12 项为 `1,2,3,4,5,6,7,8,9,11,22,33`。

### 04.05
```js
function indexOfText(text, pattern) {
  for (let i = 0; i <= text.length - pattern.length; i++) {
    let j = 0;
    while (j < pattern.length && text[i+j] === pattern[j]) j++;
    if (j === pattern.length) return i;
  }
  return -1;
}
console.log(indexOfText('banana','ana'));
```
结果：`1`；空模式返回 `0`。

### 04.06
```js
const math = {
  current: 0,
  add(...values) { this.current += values.reduce((a,b)=>a+b,0); return this; },
  minus(value) { this.current -= value; return this; },
  times(value) { this.current *= value; return this; },
  value() { return this.current; }
};
console.log(math.add(2,4).minus(3).times(2).value());
```
结果：`6`；再次调用会延续当前值。

### 04.07
```js
function negativeIndex(array) {
  return new Proxy(array, {get(target,key,receiver) {
    if (typeof key === 'string' && /^-[1-9]\d*$/.test(key)) {
      const i = target.length + Number(key);
      return i < 0 ? undefined : Reflect.get(target,String(i),receiver);
    }
    return Reflect.get(target,key,receiver);
  }});
}
console.log(negativeIndex([10,20])[-1]);
```
结果：`20`；Symbol 键正常传给 `Reflect.get`。

### 04.08
```js
function threeGroups(numbers) {
  const groups = [[],[],[]], totals = [0,0,0];
  for (const value of [...numbers].sort((a,b)=>b-a)) {
    const i = totals.indexOf(Math.min(...totals));
    groups[i].push(value); totals[i] += value;
  }
  return {groups, totals};
}
console.log(threeGroups([11,42,23,4,5,6]).totals);
```
结果：示例为 `[42,23,26]`；这是贪心近似，不能保证最优。

### 04.09
```js
function zigzagRows(matrix) {
  return matrix.flatMap((row,i) => i % 2 ? [...row].reverse() : row);
}
console.log(zigzagRows([[1,2],[3,4]]));
```
结果：按行蛇形输出 `[1,2,4,3]`；对角线之字形需另一算法。

### 04.10
```js
function maximum(items) {
  if (!items.length) throw RangeError('empty');
  return items.reduce((a,b) => a > b ? a : b);
}
console.log(maximum([3,8,2]));
```
结果：`8`。

### 04.11
```js
function fib(n, a = 0, b = 1) { return n === 0 ? a : fib(n-1,b,a+b); }
console.log(fib(7));
```
结果：`13`；大输入改循环，JS 不保证尾调用优化。

### 04.12
```js
const routes = {'/': () => 'Home', '/about': () => 'About'};
function renderRoute() { document.querySelector('#app').textContent = (routes[location.pathname] ?? (()=>'404'))(); }
function go(path) { history.pushState(null,'',path); renderRoute(); }
addEventListener('popstate',renderRoute); renderRoute();
```
结果：`go('/about')` 后 `#app` 显示 `About`；服务器需把直达路径回退到页面入口。

### 04.13
```js
const store = {
  set(key,value) { localStorage.setItem(key,JSON.stringify(value)); },
  get(key) { const raw = localStorage.getItem(key); return raw === null ? null : JSON.parse(raw); }
};
store.set('a',{n:1}); console.log(store.get('a'));
```
结果：`{n:1}`；生产代码还要处理存储禁用、配额和损坏 JSON。

### 04.14
```js
const result = Array.from({length:1000},(_,i)=>i+1)
  .filter(n => String(n) === [...String(n)].reverse().join(''));
console.log(result.at(-1));
```
结果：`999`，是 1–1000 范围最后一个回文数。

### 04.15
```js
function randomHex(bytes = 4) {
  const values = crypto.getRandomValues(new Uint8Array(bytes));
  return [...values].map(x => x.toString(16).padStart(2,'0')).join('');
}
console.log(randomHex(4).length);
```
结果：`8`；具体字符每次随机变化。

### 04.16
```js
function judge(text, abbreviation) {
  return [...text].filter(ch => /[A-Z]/.test(ch)).join('') === abbreviation;
}
console.log(judge('ByteDance','BD'), judge('Bytedance','BD'));
```
结果：`true false`。

### 04.17
```js
function runLength(text) {
  let out = '';
  for (let i = 0; i < text.length;) {
    let j = i + 1; while (j < text.length && text[j] === text[i]) j++;
    out += text[i] + (j-i); i = j;
  }
  return out;
}
console.log(runLength('aaabb'));
```
结果：`a3b2`；原文含数字时需加分隔符防歧义。

### 04.18
```js
function groupProducts(products) {
  const groups = new Map();
  for (const {name,categories} of products) for (const category of categories) {
    if (!groups.has(category)) groups.set(category,[]);
    groups.get(category).push(name);
  }
  return [...groups].map(([name,categories]) => ({name,categories}));
}
console.log(groupProducts([{name:'苹果',categories:['水果','热门']}]));
```
结果：`[{name:'水果',categories:['苹果']},{name:'热门',categories:['苹果']}]`。

### 04.19
```js
function expand(text) {
  return (text.match(/\d+\D+/g) ?? []).map(part => {
    const [,count,word] = part.match(/^(\d+)(\D+)$/);
    return word.repeat(Number(count));
  }).join('');
}
console.log(expand('3a2we'));
```
结果：`aaawewe`；格式非法时应拒绝，而不是悄悄忽略残余片段。

### 04.20
```js
function observe(object, onChange) {
  for (const key of Object.keys(object)) {
    let value = object[key];
    Object.defineProperty(object,key,{enumerable:true,configurable:true,
      get() { return value; },
      set(next) { if (!Object.is(value,next)) { value = next; onChange(key,next); } }
    });
  }
  return object;
}
const state = observe({n:1}, console.log); state.n = 2;
```
结果：输出 `n 2`；新增属性不会自动被监听。

### 04.21
```js
const x = {}, same = x;
console.log('a' === 'a', x === same, {} === {}, (()=>{}) === (()=>{}));
```
结果：`true true false false`；对象和函数按引用比较。

### 04.22
```js
function removeBAndAC(text) {
  const stack = [];
  for (const ch of text) {
    if (ch === 'b') continue;
    if (ch === 'c' && stack.at(-1) === 'a') stack.pop();
    else stack.push(ch);
  }
  return stack.join('');
}
console.log(removeBAndAC('abacbc'));
```
结果：空字符串 `''`；删除后新相邻的 `ac` 也会消除。

### 04.23
```js
const values = ['x', new String('y'), 3, {}];
console.log(values.filter(x => typeof x === 'string' || Object.prototype.toString.call(x) === '[object String]'));
```
结果：包含 `'x'` 和 `String {'y'}` 两项。

### 04.24
```js
function before(n, fn) {
  let count = 0, last;
  return function(...args) { if (count < n) { count++; last = fn.apply(this,args); } return last; };
}
const f = before(2, x => x*2);
console.log(f(1),f(2),f(3));
```
结果：`2 4 4`；按原讨论示例执行前 n 次。

### 04.25
```js
function myLog(...args) { console.log(...args); }
myLog('hello', 2);
```
结果：控制台输出 `hello 2`；只是调用包装器。

### 04.26
```js
function num(value) {
  return {add(x){value+=x; return this;}, minus(x){value-=x; return this;}, value(){return value;}};
}
console.log(num(5).add(3).minus(2).value());
```
结果：`6`；避免污染 `Number.prototype`。

### 04.27
```js
function binary(n) {
  if (!Number.isSafeInteger(n) || n < 0) throw RangeError('n');
  if (n === 0) return '0';
  let out = ''; while (n) { out = (n % 2) + out; n = Math.floor(n/2); }
  return out;
}
console.log(binary(13));
```
结果：`1101`。

### 04.28
```js
function removeSelf(node) { node.parentNode?.removeChild(node); }
const item = document.createElement('p'); document.body.append(item); removeSelf(item);
console.log(item.isConnected);
```
结果：`false`；现代浏览器也可直接 `item.remove()`。

### 04.29
```js
function countLetters(text) {
  const counts = new Map();
  for (const ch of text) if (/[A-Za-z]/.test(ch)) counts.set(ch,(counts.get(ch) ?? 0)+1);
  return Object.fromEntries(counts);
}
console.log(countLetters('aAb!a'));
```
结果：`{a:2,A:1,b:1}`；示例区分大小写，仅计 ASCII 字母。

### 04.30
```js
function triangle(height) {
  return Array.from({length:height},(_,i) => ' '.repeat(height-i-1)+'*'.repeat(2*i+1)).join('\n');
}
console.log(triangle(3));
```
结果：输出三行：`  *`、` ***`、`*****`。

### 04.31
```js
const a = (() => { let count = 0; return () => ++count % 2 ? 1 : 2; })();
console.log(a(),a(),a());
```
结果：`1 2 1`。

### 04.32
```js
function nearest(values,target) {
  if (!values.length) throw RangeError('empty');
  return values.reduce((best,x) => Math.abs(x-target) < Math.abs(best-target) ? x : best);
}
console.log(nearest([3,56,56,23,7,76,-2,345,45,76,3],37));
```
结果：`45`；并列时保留先出现的值。

### 04.33
```js
function sumTo(n) { return n * (n+1) / 2; }
console.log(sumTo(100));
```
结果：`5050`；适用于 1 到 n 的整数求和。

### 04.34
```js
let a = {old:true}, b = a, c = null;
a.x = a = {new:true};
console.log(a.new, b.x === a, c);
```
结果：`true true null`；先固定旧对象的 `a.x` 引用，再执行右侧的 `a={...}`。

### 04.35
```js
function frequencies(text) {
  return [...text].reduce((out,ch) => (out[ch]=(out[ch]??0)+1,out),Object.create(null));
}
console.log({...frequencies('aab')});
```
结果：`{a:2,b:1}`；原题“1 可省略”的输出格式未确定。

### 04.36
```js
console.log(Array(10).fill(1), Array.from({length:10},()=>1), [...Array(10)].map(()=>1));
```
结果：三种写法都产生 10 个 `1`；`Array(10).map` 本身不会访问空位。

### 04.37
```js
function groupSorted(words) {
  const out = {};
  for (const word of words) (out[word[0]] ??= []).push(word);
  for (const group of Object.values(out)) group.sort();
  return out;
}
console.log(groupSorted(['zm','za','b','lm','ln','k']));
```
结果：`{z:['za','zm'],b:['b'],l:['lm','ln'],k:['k']}`；对象键顺序按首次出现。

### 04.38
```js
function ranges(nums) {
  const out = [];
  for (let i = 0; i < nums.length;) {
    let j = i; while (j+1 < nums.length && nums[j+1] === nums[j]+1) j++;
    out.push(i === j ? String(nums[i]) : `${nums[i]}->${nums[j]}`);
    i = j+1;
  }
  return out;
}
console.log(ranges([0,1,2,4,5,7,13,15,16]));
```
结果：`['0->2','4->5','7','13','15->16']`。

### 04.39
```js
function numberDuplicates(values) {
  const total = new Map(), seen = new Map();
  values.forEach(x => total.set(x,(total.get(x)??0)+1));
  return values.map(x => {
    seen.set(x,(seen.get(x)??0)+1);
    return total.get(x) > 1 ? `${x}${seen.get(x)}` : x;
  });
}
console.log(numberDuplicates(['ab','c','ab','d','c']));
```
结果：`['ab1','c1','ab2','d','c2']`。

### 04.40
```js
function removeEmpty(object) {
  return Object.fromEntries(Object.entries(object).filter(([,value]) => value !== null && value !== undefined && value !== ''));
}
console.log(removeEmpty({a:0,b:'',c:null,d:false}));
```
结果：`{a:0,d:false}`；“空”在此限定为 `null/undefined/''`。

### 04.41
```js
function equal(a,b) {
  if (Object.is(a,b)) return true;
  if (!a || !b || typeof a !== 'object' || typeof b !== 'object') return false;
  const ak = Reflect.ownKeys(a), bk = Reflect.ownKeys(b);
  return ak.length === bk.length && ak.every(key => bk.includes(key) && equal(a[key],b[key]));
}
console.log(equal({x:[1,2]},{x:[1,2]}));
```
结果：`true`；仅适用于无循环的普通对象和数组，其他内建类型需特判。

### 04.42
```js
function nextGreaterIndexes(nums) {
  const out = Array(nums.length).fill(-1), stack = [];
  nums.forEach((value,i) => {
    while (stack.length && nums[stack.at(-1)] < value) out[stack.pop()] = i;
    stack.push(i);
  });
  return out;
}
console.log(nextGreaterIndexes([2,1,3]));
```
结果：`[2,2,-1]`，时间 O(n)。

### 04.43
```js
function topThree(tags) {
  const counts = new Map(); for (const tag of tags) counts.set(tag,(counts.get(tag)??0)+1);
  return [...counts].sort((a,b)=>b[1]-a[1] || a[0].localeCompare(b[0])).slice(0,3);
}
console.log(topThree(['a','b','a','c','c','a']));
```
结果：`[['a',3],['c',2],['b',1]]`。

### 04.44
```js
function isPrime(n) {
  if (!Number.isInteger(n) || n < 2) return false;
  for (let d = 2; d*d <= n; d++) if (n%d === 0) return false;
  return true;
}
console.log([1,2,17,18].map(isPrime));
```
结果：`[false,true,true,false]`。

### 04.45
```js
function formatDate(date) {
  const pad = n => String(n).padStart(2,'0');
  return `${date.getFullYear()}-${pad(date.getMonth()+1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`;
}
console.log(formatDate(new Date(2026,0,2,3,4)));
```
结果：本地时区下输出 `2026-01-02 03:04`。

### 04.46
```js
function jsonp(url, timeout = 5000) {
  return new Promise((resolve,reject) => {
    const name = `jsonp_${crypto.randomUUID().replaceAll('-','')}`;
    const script = document.createElement('script');
    const timer = setTimeout(() => done(new Error('timeout')),timeout);
    function done(error,data) { clearTimeout(timer); script.remove(); delete window[name]; error ? reject(error) : resolve(data); }
    window[name] = data => done(null,data);
    script.onerror = () => done(new Error('load failed'));
    const target = new URL(url,location.href); target.searchParams.set('callback',name);
    script.src = target.href; document.head.append(script);
  });
}
```
结果：服务端调用指定回调时返回数据；仅对可信脚本源使用。

### 04.47
```js
function reverseDomain(host) { return host.split('.').reverse().join('.'); }
console.log(reverseDomain('www.baidu.taobao.com'));
```
结果：`com.taobao.baidu.www`。

### 04.48
```js
function queryObject(url) {
  const out = Object.create(null);
  for (const [key,value] of new URL(url).searchParams) {
    if (key in out) out[key] = Array.isArray(out[key]) ? [...out[key],value] : [out[key],value];
    else out[key] = value;
  }
  return out;
}
console.log(queryObject('https://x.test/?a=1&a=2'));
```
结果：`{a:['1','2']}`。

### 04.49
```js
function counter() {
  let n = 0;
  const count = () => ++n;
  count.reset = () => { n = 0; };
  return count;
}
const c = counter(); console.log(c(),c()); c.reset(); console.log(c());
```
结果：`1 2`，然后 `1`。

### 04.50
```js
function randomColor() {
  return '#' + [...crypto.getRandomValues(new Uint8Array(3))]
    .map(byte => byte.toString(16).padStart(2,'0')).join('');
}
console.log(/^#[0-9a-f]{6}$/.test(randomColor()));
```
结果：`true`；具体颜色随机。

### 04.51
```js
const list = [1,2], alias = list;
list.length = 0;
console.log(list,alias);
```
结果：两个引用都看到空数组 `[]`；`list=[]` 只会改变一个变量的引用。

### 04.52
```js
function relation(a,b) {
  const count = xs => xs.reduce((m,x) => m.set(x,(m.get(x)??0)+1),new Map());
  const x = count(a), y = count(b);
  const subset = (p,q) => [...p].every(([key,n]) => n <= (q.get(key)??0));
  const ab = subset(x,y), ba = subset(y,x);
  return ab && ba ? 0 : ab ? 1 : ba ? 2 : -1;
}
console.log(relation([1],[1,1]), relation([1,2],[2,1]));
```
结果：`1 0`。

### 04.53
```js
const a = {x:1,shared:'a'}, b = {y:2,shared:'b'};
console.log({...a,...b});
```
结果：`{x:1,shared:'b',y:2}`；这是浅合并。

### 04.54
```js
function* integers() { let n = 0; while (true) yield n++; }
const it = integers(); console.log(it.next().value,it.next().value,it.next().value);
```
结果：`0 1 2`；按需产生值，不建立真正无限长数组。

### 04.55
```js
function matrix(text) {
  if (!text.trim()) return [];
  return text.trim().split(/\r?\n/).map(line => line.trim().split(/\s+/));
}
console.log(matrix('1  2\n3 4'));
```
结果：`[['1','2'],['3','4']]`；要数字时再逐项 `Number`。

### 04.56
```js
function take(iterable,count) {
  const iterator=iterable[Symbol.iterator](),out=[];
  try { for(let i=0;i<count;i++){const step=iterator.next();if(step.done)break;out.push(step.value);} }
  finally { iterator.return?.(); }
  return out;
}
console.log(take(new Set([10,20]),2));
```
结果：`[10,20]`；这是按迭代协议提取前两项，默认值和剩余元素需按具体模式扩展。

### 04.57
```js
const a = [1,2], b = [3,4];
console.log([...a,...b]);
```
结果：`[1,2,3,4]`，元素仍保持原引用。

### 04.58
```js
function sets(a,b) {
  const A = new Set(a), B = new Set(b);
  return {intersection:[...A].filter(x=>B.has(x)), union:[...new Set([...A,...B])], difference:[...A].filter(x=>!B.has(x))};
}
console.log(sets([1,1,2],[2,3]));
```
结果：交集 `[2]`、并集 `[1,2,3]`、A−B `[1]`。

### 04.59
```js
function product(arrays) {
  return arrays.reduce((rows,items) => rows.flatMap(row => items.map(item => [...row,item])),[[]]);
}
console.log(product([[1,2],['a','b']]));
```
结果：`[[1,'a'],[1,'b'],[2,'a'],[2,'b']]`。

### 04.60
```js
function hasCycle(value, active = new WeakSet()) {
  if (!value || typeof value !== 'object') return false;
  if (active.has(value)) return true;
  active.add(value);
  const found = Reflect.ownKeys(value).some(key => hasCycle(value[key],active));
  active.delete(value); return found;
}
const a = {}; a.self = a; console.log(hasCycle(a));
```
结果：`true`；共享子对象但无回边时返回 `false`。

### 04.61
```js
function smallestInOriginalOrder(values,k) {
  if (!Number.isInteger(k) || k < 0 || k > values.length) throw RangeError('k');
  const need = new Map();
  for (const x of [...values].sort((a,b)=>a-b).slice(0,k)) need.set(x,(need.get(x)??0)+1);
  return values.filter(x => { const n = need.get(x)??0; if (!n) return false; need.set(x,n-1); return true; });
}
console.log(smallestInOriginalOrder([5,1,3,2],2));
```
结果：`[1,2]`，保持原数组相对顺序。

### 04.62
```js
function unflatten(entries) {
  const out = Object.create(null);
  for (const [path,value] of Object.entries(entries)) {
    const keys = path.split('.'); if (keys.some(k => ['__proto__','prototype','constructor'].includes(k))) throw Error('unsafe key');
    let node = out; for (const key of keys.slice(0,-1)) node = node[key] ??= Object.create(null);
    node[keys.at(-1)] = value;
  }
  return out;
}
console.log(unflatten({'a.b':1}).a.b);
```
结果：`1`；数组索引和路径冲突未实现。

### 04.63
```js
function flattenObject(object, prefix = '', out = {}) {
  for (const [key,value] of Object.entries(object)) {
    const path = prefix ? `${prefix}.${key}` : key;
    if (value && typeof value === 'object' && !Array.isArray(value)) flattenObject(value,path,out);
    else out[path] = value;
  }
  return out;
}
console.log(flattenObject({a:{b:1}}));
```
结果：`{'a.b':1}`；循环引用与键本身含点号需另定规则。

### 04.64
```js
function once(fn) {
  let called = false, result;
  return function(...args) { if (!called) { result = fn.apply(this,args); called = true; } return result; };
}
const f = once(x => x*2); console.log(f(2),f(9));
```
结果：`4 4`；同步抛错时可重试。

### 04.65
```js
function chain(value) { return {add(n){value+=n;return this;},times(n){value*=n;return this;},value(){return value;}}; }
console.log(chain(2).add(3).times(4).value());
```
结果：`20`。

### 04.66
```js
function partial(fn,...bound) { return function(...rest) { return fn.apply(this,[...bound,...rest]); }; }
console.log(partial((a,b,c)=>a+b+c,1,2)(3));
```
结果：`6`。

### 04.67
```js
function pipe(...functions) { return input => functions.reduce((value,fn)=>fn(value),input); }
console.log(pipe(x=>x+1,x=>x*2)(3));
```
结果：`8`，从左到右执行。

### 04.68
```js
function delegate(root,selector,handler) {
  const listener = event => { const target = event.target.closest?.(selector); if (target && root.contains(target)) handler(event,target); };
  root.addEventListener('click',listener);
  return () => root.removeEventListener('click',listener);
}
const off = delegate(document.body,'button',(_,button)=>console.log(button.textContent));
```
结果：点击 `body` 内的按钮会输出按钮文本；调用 `off()` 后停止。

### 04.69
```js
function typeOf(value) { return Object.prototype.toString.call(value).slice(8,-1).toLowerCase(); }
console.log(typeOf(null),typeOf([]),typeOf(new Date()));
```
结果：`null array date`；自定义 `Symbol.toStringTag` 可影响结果。

### 04.70
```js
function toArray(arrayLike) { return Array.from(arrayLike); }
console.log(toArray({0:'a',1:'b',length:2}));
```
结果：`['a','b']`。

### 04.71
```js
function preloadImage(url) { const image = new Image(); image.src = url; return image; }
const image = preloadImage('/banner.webp');
```
结果：浏览器开始加载图片；`image.complete` 可检查加载完成状态。

### 04.72
```js
const observer = new IntersectionObserver(entries => {
  for (const entry of entries) if (entry.isIntersecting) {
    const image = entry.target; image.src = image.dataset.src; observer.unobserve(image);
  }
});
document.querySelectorAll('img[data-src]').forEach(image => observer.observe(image));
```
结果：图片进入视口附近时设置 `src` 并取消观察。

### 04.73
```js
function unique(values) { return [...new Set(values)]; }
console.log(unique([1,1,NaN,NaN]));
```
结果：`[1,NaN]`；对象按引用去重。

### 04.74
```js
function debounce(fn,ms) { let id; return (...args) => { clearTimeout(id); id=setTimeout(()=>fn(...args),ms); }; }
function throttle(fn,ms) { let last=-Infinity; return (...args) => { const now=Date.now(); if(now-last>=ms){last=now;fn(...args);} }; }
```
结果：防抖在停止触发后执行；节流在时间窗口内最多执行一次。

### 04.75
```js
function compose(...fns) { return x => fns.reduceRight((value,fn)=>fn(value),x); }
console.log(compose(x=>x+1,x=>x*2)(3));
```
结果：`7`；Koa 洋葱模型的 `await next()` 需单独实现中间件调度。

### 04.76
```js
function sum(x,y) { return arguments.length === 2 ? x+y : next => x+next; }
console.log(sum(2,3),sum(2)(3),sum(2,0));
```
结果：`5 5 2`。

### 04.77
```js
function curry(fn,...collected) {
  return (...args) => {
    const all = [...collected,...args];
    return all.length >= fn.length ? fn(...all) : curry(fn,...all);
  };
}
console.log(curry((a,b,c)=>a+b+c)(1)(2)(3));
```
结果：`6`；默认参数和剩余参数会影响 `fn.length`。

### 05.01
```js
class Subject {
  #observers = new Set();
  subscribe(fn) { this.#observers.add(fn); return () => this.#observers.delete(fn); }
  notify(value) { for (const fn of [...this.#observers]) fn(value); }
}
const subject = new Subject(); const off = subject.subscribe(console.log); subject.notify(3); off();
```
结果：输出 `3` 一次。

### 06.01
```js
function dom2json(node) {
  if (node.nodeType === Node.TEXT_NODE) return node.textContent;
  if (node.nodeType !== Node.ELEMENT_NODE) return null;
  return {type:node.tagName.toLowerCase(), attributes:Object.fromEntries([...node.attributes].map(a=>[a.name,a.value])), children:[...node.childNodes].map(dom2json).filter(x=>x!==null)};
}
console.log(dom2json(document.createElement('div')).type);
```
结果：`div`；文本节点返回文本。

### 06.02
```js
function depth(node) { return node ? 1 + Math.max(0,...(node.children??[]).map(depth)) : 0; }
console.log(depth({children:[{children:[{}]}]}));
```
结果：`3`。

### 06.03
```js
function findNames(nodes,id,path=[]) {
  for (const node of nodes) {
    const next = [...path,node.name];
    if (node.id === id) return next;
    const found = findNames(node.children??[],id,next); if (found) return found;
  }
  return null;
}
console.log(findNames([{id:1,name:'A',children:[{id:2,name:'B'}]}],2));
```
结果：`['A','B']`。

### 06.04
```js
function walk(nodes,visit) { for (const node of nodes) { visit(node); walk(node.children??[],visit); } }
walk([{name:'A',children:[{name:'B'}]}],node=>console.log(node.name));
```
结果：依次输出 `A`、`B`；循环引用需额外检测。

### 06.05
```js
function collect(nodes,key) { const out=[]; (function visit(items){ for(const node of items){ if(key in node) out.push(node[key]); visit(node.children??[]); } })(nodes); return out; }
console.log(collect([{name:'A',children:[{name:'B'}]}],'name'));
```
结果：`['A','B']`；这里假设要收集全树指定属性。

### 06.06
```js
function childPath(nodes,id,path=[]) {
  for (let i=0;i<nodes.length;i++) { const next=[...path,i]; if(nodes[i].id===id) return next; const found=childPath(nodes[i].children??[],id,next); if(found) return found; }
  return null;
}
console.log(childPath([{id:1,children:[{id:2}]}],2));
```
结果：`[0,0]`，表示从根数组到 `children` 的索引路径。

### 06.07
```js
function parseTreeJSON(text) {
  const value = JSON.parse(text);
  if (!Array.isArray(value)) throw TypeError('expected node array');
  return value;
}
console.log(parseTreeJSON('[{"name":"A","children":[]}]')[0].name);
```
结果：`A`；假设输入是 JSON 字符串，缩进文本需另一解析器。

### 06.08
```js
function pathsWithSum(root,target) {
  const out=[];
  function visit(node,sum,path) { if(!node) return; const next=[...path,node.value], total=sum+node.value; if(!node.children?.length && total===target) out.push(next); for(const child of node.children??[]) visit(child,total,next); }
  visit(root,0,[]); return out;
}
console.log(pathsWithSum({value:1,children:[{value:2},{value:3}]},3));
```
结果：`[[1,2]]`；这里统计根到叶的路径。

### 06.09
```js
function getNames(root) { return [root.name,...(root.children??[]).flatMap(getNames)]; }
console.log(getNames({name:'A',children:[{name:'B'}]}));
```
结果：`['A','B']`；假设题意是获取整棵树的名称。

### 07.01
```js
function forEachLike(array,callback,thisArg) {
  if(typeof callback!=='function') throw TypeError('callback');
  const obj=Object(array), len=obj.length>>>0;
  for(let i=0;i<len;i++) if(i in obj) callback.call(thisArg,obj[i],i,obj);
}
forEachLike([1,,3],console.log);
```
结果：只回调索引 0 和 2，函数返回 `undefined`。

### 07.02
```js
function filterLike(array,callback,thisArg) {
  if(typeof callback!=='function') throw TypeError('callback');
  const obj=Object(array), out=[], len=obj.length>>>0;
  for(let i=0;i<len;i++) if(i in obj && callback.call(thisArg,obj[i],i,obj)) out.push(obj[i]);
  return out;
}
console.log(filterLike([1,,2,3],x=>x>1));
```
结果：`[2,3]`。

### 07.03
```js
function reduceLike(array,callback,...initial) {
  if(typeof callback!=='function') throw TypeError('callback');
  const obj=Object(array), len=obj.length>>>0; let i=0, acc;
  if(initial.length) acc=initial[0];
  else { while(i<len && !(i in obj)) i++; if(i===len) throw TypeError('empty'); acc=obj[i++]; }
  for(;i<len;i++) if(i in obj) acc=callback(acc,obj[i],i,obj);
  return acc;
}
console.log(reduceLike([1,,3],(a,b)=>a+b,0));
```
结果：`4`；空数组无初值会抛 `TypeError`。

### 07.04
```js
function fillLike(array,value,start=0,end=array.length) {
  const len=array.length, index=n=>Math.min(len,Math.max(0,n<0?len+n:n));
  for(let i=index(start);i<index(end);i++) array[i]=value;
  return array;
}
console.log(fillLike([1,2,3],9,-2));
```
结果：`[1,9,9]`，原数组也被修改。

### 07.05
```js
function includesLike(array,search,from=0) {
  const len=array.length; let i=from<0?Math.max(len+from,0):from;
  for(;i<len;i++){const value=array[i]; if(value===search || (value!==value && search!==search)) return true;}
  return false;
}
console.log(includesLike([,NaN],undefined),includesLike([NaN],NaN));
```
结果：`true true`，空位按 `undefined` 比较。

### 07.06
```js
function pushLike(array,...items) { for(const item of items) array[array.length]=item; return array.length; }
const a=[1]; console.log(pushLike(a,2,3),a);
```
结果：`3 [1,2,3]`。

### 07.07
```js
function unshiftLike(array,...items) {
  const old=array.length, count=items.length;
  for(let i=old-1;i>=0;i--) { if(i in array) array[i+count]=array[i]; else delete array[i+count]; }
  for(let i=0;i<count;i++) array[i]=items[i];
  return array.length;
}
const a=[2,3]; console.log(unshiftLike(a,1),a);
```
结果：`3 [1,2,3]`。

### 07.08
```js
function copyWithinLike(array,target,start,end=array.length) {
  const len=array.length, norm=n=>Math.min(len,Math.max(0,n<0?len+n:n));
  let to=norm(target), from=norm(start), count=Math.min(norm(end)-from,len-to);
  const step=from<to && to<from+count ? -1 : 1;
  if(step<0){from+=count-1;to+=count-1;}
  while(count-->0){ if(from in array) array[to]=array[from]; else delete array[to]; from+=step; to+=step; }
  return array;
}
console.log(copyWithinLike([1,2,3,4],1,2));
```
结果：`[1,3,4,4]`；题名 `copy` 非标准，此处按 `copyWithin` 解释。

### 07.09
```js
function getLevel(value) { return Array.isArray(value) ? 1 + Math.max(0,...value.map(getLevel)) : 0; }
console.log(getLevel([1,[2,[3]]]));
```
结果：`3`；此处约定最外层数组深度为 1。

### 07.10
```js
class MiniSet {
  #items=new Map();
  add(x){this.#items.set(x,true);return this;}
  has(x){return this.#items.has(x);}
  delete(x){return this.#items.delete(x);}
  get size(){return this.#items.size;}
  [Symbol.iterator](){return this.#items.keys();}
}
console.log([...new MiniSet().add(1).add(1).add(2)]);
```
结果：`[1,2]`；用 `Map` 复用键身份和迭代顺序。

### 07.11
```js
class MiniMap {
  #entries=[];
  #index(key){return this.#entries.findIndex(([k])=>Object.is(k,key) || k===key);}
  set(key,value){const i=this.#index(key);i<0?this.#entries.push([key,value]):this.#entries[i][1]=value;return this;}
  get(key){const i=this.#index(key);return i<0?undefined:this.#entries[i][1];}
  has(key){return this.#index(key)>=0;}
  delete(key){const i=this.#index(key);if(i<0)return false;this.#entries.splice(i,1);return true;}
  [Symbol.iterator](){return this.#entries[Symbol.iterator]();}
}
const key={};console.log(new MiniMap().set(key,3).get(key));
```
结果：`3`；这是教学简化版，完整原生迭代和性能语义尚未覆盖。

### 07.12
```js
function zpadStart(value,length){return String(value).padStart(length,'0');}
console.log(zpadStart(12,5));
```
结果：`00012`；`zpadStart` 不是标准方法。

### 07.13
```js
function assignLike(target,...sources){
  if(target==null) throw TypeError('target');
  const out=Object(target);
  for(const source of sources) if(source!=null) for(const key of Reflect.ownKeys(Object(source))) {
    const descriptor=Object.getOwnPropertyDescriptor(Object(source),key);
    if(descriptor.enumerable) out[key]=source[key];
  }
  return out;
}
console.log(assignLike({}, {a:1},{b:2}));
```
结果：`{a:1,b:2}`，为浅拷贝。

### 07.14
```js
function isLike(x,y){return x===y ? x!==0 || 1/x===1/y : x!==x && y!==y;}
console.log(isLike(NaN,NaN),isLike(0,-0));
```
结果：`true false`。

### 07.15
```js
function stringifySubset(value){
  const seen=new WeakSet();
  function encode(x){
    if(x===null || typeof x==='boolean' || typeof x==='number') return JSON.stringify(x);
    if(typeof x==='string') return JSON.stringify(x);
    if(typeof x!=='object') return undefined;
    if(seen.has(x)) throw TypeError('cycle'); seen.add(x);
    const out=Array.isArray(x) ? `[${Array.from(x,v=>encode(v)??'null').join(',')}]`
      : `{${Object.keys(x).flatMap(k=>{const v=encode(x[k]);return v===undefined?[]:[`${JSON.stringify(k)}:${v}`]}).join(',')}}`;
    seen.delete(x); return out;
  }
  return encode(value);
}
console.log(stringifySubset({a:1,b:[true,null]}));
```
结果：`{"a":1,"b":[true,null]}`；不覆盖 `toJSON`、replacer 等完整原生语义。

### 07.16
```js
function parseJSON(text){
  let i=0;
  const space=()=>{while(/\s/.test(text[i]??'' ) && i<text.length)i++;};
  function value(){
    space();const ch=text[i];
    if(ch==='"'){let end=i+1;while(end<text.length){if(text[end]==='\\'){end+=2;continue;}if(text[end++]==='"'){const raw=text.slice(i,end);i=end;return JSON.parse(raw);}}throw SyntaxError('string');}
    if(ch==='['){i++;const out=[];space();if(text[i]===']'){i++;return out;}do{out.push(value());space();if(text[i]===']'){i++;return out;}if(text[i++]!==',')throw SyntaxError('array');}while(true);}
    if(ch==='{'){i++;const out={};space();if(text[i]==='}'){i++;return out;}do{space();if(text[i]!=='"')throw SyntaxError('key');const key=value();space();if(text[i++]!==':')throw SyntaxError('colon');const item=value();Object.defineProperty(out,key,{value:item,enumerable:true,writable:true,configurable:true});space();if(text[i]==='}'){i++;return out;}if(text[i++]!==',')throw SyntaxError('object');}while(true);}
    for(const [word,item] of [['true',true],['false',false],['null',null]])if(text.startsWith(word,i)){i+=word.length;return item;}
    const number=text.slice(i).match(/^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?/);
    if(number){i+=number[0].length;return Number(number[0]);}
    throw SyntaxError('value');
  }
  const out=value();space();if(i!==text.length)throw SyntaxError('trailing');return out;
}
console.log(parseJSON('{"a":[1,true,null]}').a);
```
结果：`[1,true,null]`；字符串转义委托原生 `JSON.parse`，对象与数组由递归下降解析。

### 07.17
```js
function trimLike(text){return String(text).replace(/^\s+|\s+$/g,'');}
console.log(trimLike('  hi \n'));
```
结果：`hi`；这是常见近似版。

### 07.18
```js
function newLike(Constructor,...args){
  if(typeof Constructor!=='function') throw TypeError('constructor');
  const instance=Object.create(Constructor.prototype);
  const returned=Constructor.apply(instance,args);
  return returned!==null && (typeof returned==='object'||typeof returned==='function') ? returned : instance;
}
function Person(name){this.name=name;} console.log(newLike(Person,'Ada').name);
```
结果：`Ada`；类构造函数不能通过 `.apply` 调用，完整语义应使用 `Reflect.construct`。

### 07.19
```js
function repeatLike(text,count){
  if(!Number.isFinite(count)||count<0) throw RangeError('count');
  let n=Math.trunc(count),chunk=String(text),out='';
  while(n){if(n%2)out+=chunk;n=Math.floor(n/2);if(n)chunk+=chunk;}
  return out;
}
console.log(repeatLike('ab',3));
```
结果：`ababab`。

### 07.20
```js
function includesText(text,search,position=0){
  if(search instanceof RegExp) throw TypeError('RegExp');
  return String(text).indexOf(String(search),Math.max(0,Math.trunc(position)||0))!==-1;
}
console.log(includesText('hello','ell'));
```
结果：`true`；跨 realm 正则和 `Symbol.match` 需完整原生语义处理。

### 08.01
```js
function chunk(array,size){
  if(!Number.isInteger(size)||size<1) throw RangeError('size');
  const out=[];for(let i=0;i<array.length;i+=size)out.push(array.slice(i,i+size));return out;
}
console.log(chunk([1,2,3,4,5],2));
```
结果：`[[1,2],[3,4],[5]]`。

### 09.01
```js
function isPlainObject(value){
  if(value===null||typeof value!=='object') return false;
  const proto=Object.getPrototypeOf(value);
  return proto===null||proto===Object.prototype;
}
console.log(isPlainObject({}),isPlainObject([]));
```
结果：`true false`；跨 realm 需更完整判断。

### 10.01
```js
function promisify(fn){return function(...args){return new Promise((resolve,reject)=>{
  fn.call(this,...args,(error,value)=>error?reject(error):resolve(value));
});};}
const read=promisify(require('node:fs').readFile);
read('package.json','utf8').then(text=>console.log(text.length));
```
结果：文件存在时输出长度；失败时 Promise 拒绝。

### 11.01
```js
const checks={qq:/^[1-9]\d{4,}$/,hexColor:/^#[0-9a-fA-F]{6}$/,email:/^[^\s@]+@[^\s@]+\.[^\s@]+$/};
console.log(checks.qq.test('12345'),checks.hexColor.test('#aBc123'),checks.email.test('a@b.com'));
```
结果：`true true true`；手机号号段和邮箱有效性需按业务规则与实际验证处理。

### 11.02
```js
function swapCase(text){return text.replace(/[A-Za-z]/g,ch=>ch===ch.toLowerCase()?ch.toUpperCase():ch.toLowerCase());}
console.log(swapCase('Ab1'));
```
结果：`aB1`。

### 11.03
```js
const startsOrEndsWithDigit = text => /^\d|\d$/.test(text);
console.log(startsOrEndsWithDigit('1a'),startsOrEndsWithDigit('a2'),startsOrEndsWithDigit('ab'));
```
结果：`true true false`；这里是“首或尾”。

### 11.04
```js
console.log(' a b '.trim(), ' a b '.replace(/\s/g,''));
```
结果：分别是 `'a b'` 与 `'ab'`；前者只去两端。

### 11.05
```js
console.log('a1中B'.replace(/[A-Za-z]/g,''));
```
结果：`1中`；仅删除 ASCII 字母。

### 11.06
```js
function snake(text){return text.replace(/([A-Z]+)([A-Z][a-z])/g,'$1_$2').replace(/([a-z0-9])([A-Z])/g,'$1_$2').toLowerCase();}
console.log(snake('XMLHttpRequest'));
```
结果：`xml_http_request`。

### 11.07
```js
function snakeKeys(value){
  if(Array.isArray(value)) return value.map(snakeKeys);
  if(value===null||typeof value!=='object') return value;
  return Object.fromEntries(Object.entries(value).map(([key,item])=>[snake(key),snakeKeys(item)]));
}
function snake(text){return text.replace(/([A-Z]+)([A-Z][a-z])/g,'$1_$2').replace(/([a-z0-9])([A-Z])/g,'$1_$2').toLowerCase();}
console.log(snakeKeys({userName:'Ada'}));
```
结果：`{user_name:'Ada'}`；循环引用需加 `WeakMap`。

### 11.08
```js
const hasThreeDigits = text => /\d{3}/.test(text);
console.log(hasThreeDigits('a123b'),hasThreeDigits('a12b'));
```
结果：`true false`；这里指连续三个数字字符，不要求数值递增。

### 11.09
```js
function innerParentheses(text){
  const stack=[],out=[];
  for(let i=0;i<text.length;i++){
    if(text[i]==='(')stack.push(i);
    else if(text[i]===')'){if(!stack.length)throw Error('unbalanced');const start=stack.pop();out.push(text.slice(start,i+1));}
  }
  if(stack.length)throw Error('unbalanced');return out;
}
console.log(innerParentheses('((2+3)+(3*4))+2'));
```
结果：`['(2+3)','(3*4)','((2+3)+(3*4))']`；输出格式与原题样例不同，需先确认括号保留规则。

### 12.01
```js
function bubble(a){a=[...a];for(let end=a.length-1;end>0;end--){let changed=false;for(let i=0;i<end;i++)if(a[i]>a[i+1]){[a[i],a[i+1]]=[a[i+1],a[i]];changed=true;}if(!changed)break;}return a;}
console.log(bubble([3,1,2]));
```
结果：`[1,2,3]`。

### 12.02
```js
function selection(a){a=[...a];for(let i=0;i<a.length;i++){let min=i;for(let j=i+1;j<a.length;j++)if(a[j]<a[min])min=j;[a[i],a[min]]=[a[min],a[i]];}return a;}
console.log(selection([3,1,2]));
```
结果：`[1,2,3]`。

### 12.03
```js
function quick(a){if(a.length<2)return [...a];const [pivot,...rest]=a;return [...quick(rest.filter(x=>x<pivot)),pivot,...quick(rest.filter(x=>x>=pivot))];}
console.log(quick([3,1,2]));
```
结果：`[1,2,3]`；示例用额外数组，非原地快排。

### 12.04
```js
function insertion(a){a=[...a];for(let i=1;i<a.length;i++){const value=a[i];let j=i-1;while(j>=0&&a[j]>value){a[j+1]=a[j];j--;}a[j+1]=value;}return a;}
console.log(insertion([3,1,2]));
```
结果：`[1,2,3]`。

### 12.05
```js
function mergeSort(a){if(a.length<2)return [...a];const mid=a.length>>1,left=mergeSort(a.slice(0,mid)),right=mergeSort(a.slice(mid)),out=[];let i=0,j=0;while(i<left.length&&j<right.length)out.push(left[i]<=right[j]?left[i++]:right[j++]);return [...out,...left.slice(i),...right.slice(j)];}
console.log(mergeSort([3,1,2]));
```
结果：`[1,2,3]`，相等元素优先取左边保持稳定。

### 12.06
```js
function radix(a){if(a.some(x=>!Number.isSafeInteger(x)||x<0))throw RangeError('nonnegative integers only');let out=[...a];for(let place=1;out.some(x=>x>=place);place*=10){const buckets=Array.from({length:10},()=>[]);for(const x of out)buckets[Math.floor(x/place)%10].push(x);out=buckets.flat();}return out;}
console.log(radix([21,3,12]));
```
结果：`[3,12,21]`；仅处理非负安全整数。

### 12.07
```js
function counting(a){if(!a.length)return [];const min=Math.min(...a),max=Math.max(...a);if(!a.every(Number.isInteger)||max-min>1e6)throw RangeError('range');const counts=Array(max-min+1).fill(0);for(const x of a)counts[x-min]++;return counts.flatMap((n,i)=>Array(n).fill(i+min));}
console.log(counting([3,1,2,1]));
```
结果：`[1,1,2,3]`；大值域不适合该实现。

### 12.08
```js
function shell(a){a=[...a];for(let gap=Math.floor(a.length/2);gap>0;gap=Math.floor(gap/2))for(let i=gap;i<a.length;i++){const x=a[i];let j=i;while(j>=gap&&a[j-gap]>x){a[j]=a[j-gap];j-=gap;}a[j]=x;}return a;}
console.log(shell([3,1,2]));
```
结果：`[1,2,3]`。

### 12.09
```js
function bucket(a){if(!a.length)return [];const buckets=Array.from({length:10},()=>[]);for(const x of a){if(x<0||x>=1)throw RangeError('[0,1) only');buckets[Math.floor(x*10)].push(x);}return buckets.flatMap(b=>b.sort((x,y)=>x-y));}
console.log(bucket([0.31,0.12,0.25]));
```
结果：`[0.12,0.25,0.31]`；此例只支持 `[0,1)`。

### 12.10
```js
function heapSort(a){a=[...a];const down=(start,end)=>{let root=start;while(root*2+1<end){let child=root*2+1;if(child+1<end&&a[child]<a[child+1])child++;if(a[root]>=a[child])break;[a[root],a[child]]=[a[child],a[root]];root=child;}};for(let i=Math.floor(a.length/2)-1;i>=0;i--)down(i,a.length);for(let end=a.length-1;end>0;end--){[a[0],a[end]]=[a[end],a[0]];down(0,end);}return a;}
console.log(heapSort([3,1,2]));
```
结果：`[1,2,3]`。
### 13.01
```tsx
function useSwipe(onSwipe: (direction:'left'|'right')=>void) {
  const start = React.useRef<number|null>(null);
  return {
    onPointerDown:(e:React.PointerEvent)=>{ start.current=e.clientX; },
    onPointerUp:(e:React.PointerEvent)=>{ if(start.current!==null && Math.abs(e.clientX-start.current)>40) onSwipe(e.clientX<start.current?'left':'right'); start.current=null; },
    onPointerCancel:()=>{start.current=null;}
  };
}
```
结果：横向移动超过 40px 时回调 `left` 或 `right`；需按实际设备补速度和滚动冲突处理。

### 13.02
```tsx
function useCarousel(length:number){
  const [index,setIndex]=React.useState(0);
  const next=()=>setIndex(i=>(i+1)%length);
  const prev=()=>setIndex(i=>(i-1+length)%length);
  return {index,next,prev};
}
// const {index,next,prev}=useCarousel(images.length);
```
结果：`next()`/`prev()` 在 `0..length-1` 循环；要求 `length>0`，完整移动端轮播需再接手势和动画。

### 13.03
```tsx
React.useEffect(() => {
  console.log('setup');
  return () => console.log('cleanup');
}, []);
```
结果：挂载后建立、卸载时清理；开发 Strict Mode 可能额外执行一次建立和清理。

### 13.04
```tsx
function useBodyScrollLock(open:boolean){
  React.useEffect(()=>{
    if(!open)return;
    const previous=document.body.style.overflow;
    document.body.style.overflow='hidden';
    return ()=>{document.body.style.overflow=previous;};
  },[open]);
}
```
结果：单弹窗打开时背景滚动锁定，关闭或卸载时恢复；多弹窗需共享锁计数。

### 13.05
```tsx
function useInterval(callback:()=>void,delay:number|null){
  const latest=React.useRef(callback);
  React.useEffect(()=>{latest.current=callback;},[callback]);
  React.useEffect(()=>{if(delay===null)return;const id=setInterval(()=>latest.current(),delay);return ()=>clearInterval(id);},[delay]);
}
```
结果：按 `delay` 调用最新回调；传 `null` 暂停。

### 13.06
```tsx
function useQuery(name:string){
  const [value,setValue]=React.useState(()=>new URLSearchParams(location.search).get(name));
  React.useEffect(()=>{const update=()=>setValue(new URLSearchParams(location.search).get(name));addEventListener('popstate',update);return ()=>removeEventListener('popstate',update);},[name]);
  return value;
}
```
结果：读取当前 URL 查询参数，并响应浏览器前进/后退；这里把 `useQuery` 解释为 URL 查询 Hook。

### 13.07
```tsx
function useRequest<T>(load:(signal:AbortSignal)=>Promise<T>){
  const [state,setState]=React.useState<{data?:T;error?:Error;loading:boolean}>({loading:false});
  const controller=React.useRef<AbortController|null>(null);
  const run=React.useCallback(async()=>{controller.current?.abort();const c=new AbortController();controller.current=c;setState({loading:true});try{const data=await load(c.signal);if(!c.signal.aborted)setState({data,loading:false});}catch(error){if(!c.signal.aborted)setState({error:error as Error,loading:false});}},[load]);
  React.useEffect(()=>()=>controller.current?.abort(),[]);
  return {...state,run,cancel:()=>controller.current?.abort()};
}
```
结果：`run()` 更新加载、成功或错误状态；新请求或卸载取消旧请求。

### 14.01
```tsx
function SelectAll({ids}:{ids:string[]}){
  const [selected,setSelected]=React.useState<Set<string>>(new Set());
  const all=ids.length>0 && ids.every(id=>selected.has(id));
  return <><input type="checkbox" aria-label="全选" checked={all} onChange={()=>setSelected(all?new Set():new Set(ids))}/>{ids.map(id=><label key={id}><input type="checkbox" checked={selected.has(id)} onChange={()=>setSelected(old=>{const next=new Set(old);next.has(id)?next.delete(id):next.add(id);return next;})}/>{id}</label>)}</>;
}
```
结果：勾选全选选中所有 id，再次点击清空；部分选择的 `indeterminate` 需用 ref 设置。

### 14.02
```tsx
function Carousel({images}:{images:string[]}){
  const [index,setIndex]=React.useState(0);
  return <div><button onClick={()=>setIndex(i=>(i-1+images.length)%images.length)}>上一张</button><img src={images[index]} alt={`第 ${index+1} 张`}/><button onClick={()=>setIndex(i=>(i+1)%images.length)}>下一张</button></div>;
}
```
结果：点击按钮在图片列表中循环切换；需保证 `images` 非空。

### 14.03
```tsx
function DataTable({rows}:{rows:Array<{id:string;name:string}>}){
  return <table><thead><tr><th scope="col">名称</th></tr></thead><tbody>{rows.map(row=><tr key={row.id}><td>{row.name}</td></tr>)}</tbody></table>;
}
```
结果：逐行显示 `name`，React 默认转义文本；加载、空、错误、分页由外层状态管理。

### 14.04
```js
function lyricAt(lines,seconds){
  let left=0,right=lines.length-1,result=-1;
  while(left<=right){const mid=(left+right)>>1;if(lines[mid].time<=seconds){result=mid;left=mid+1;}else right=mid-1;}
  return result;
}
console.log(lyricAt([{time:0,text:'A'},{time:5,text:'B'}],6));
```
结果：`1`，表示当前高亮第二行；滚动时只在索引变化时调用 `scrollIntoView`。

### 14.05
```tsx
function Suggest({search}:{search:(q:string,signal:AbortSignal)=>Promise<string[]>}){
  const [query,setQuery]=React.useState(''),[items,setItems]=React.useState<string[]>([]);
  React.useEffect(()=>{if(!query.trim()){setItems([]);return;}const c=new AbortController();const id=setTimeout(()=>search(query,c.signal).then(setItems).catch(e=>{if(e.name!=='AbortError')setItems([]);}),250);return ()=>{clearTimeout(id);c.abort();};},[query,search]);
  return <><input role="combobox" aria-expanded={items.length>0} value={query} onChange={e=>setQuery(e.target.value)}/><ul role="listbox">{items.map(x=><li role="option" aria-selected="false" key={x}>{x}</li>)}</ul></>;
}
```
结果：输入停止 250ms 后搜索；旧请求被取消。完整组合框还需键盘导航和焦点管理。

### 14.06
```tsx
function Todos(){
  const [items,setItems]=React.useState<Array<{id:string;text:string;done:boolean}>>([]),[text,setText]=React.useState('');
  return <><form onSubmit={e=>{e.preventDefault();if(text.trim())setItems(old=>[...old,{id:crypto.randomUUID(),text,done:false}]);setText('');}}><input value={text} onChange={e=>setText(e.target.value)}/><button>添加</button></form><ul>{items.map(item=><li key={item.id}><label><input type="checkbox" checked={item.done} onChange={()=>setItems(old=>old.map(x=>x.id===item.id?{...x,done:!x.done}:x))}/>{item.text}</label><button onClick={()=>setItems(old=>old.filter(x=>x.id!==item.id))}>删除</button></li>)}</ul></>;
}
```
结果：可添加、切换完成和删除任务；编辑和持久化仍需补充。

### 14.07
```tsx
function Countdown({end}:{end:number}){
  const [remaining,setRemaining]=React.useState(()=>Math.max(0,end-Date.now()));
  React.useEffect(()=>{const id=setInterval(()=>setRemaining(Math.max(0,end-Date.now())),250);return ()=>clearInterval(id);},[end]);
  return <output>{Math.ceil(remaining/1000)} 秒</output>;
}
```
结果：显示剩余秒数；后台恢复后根据结束时间校准。

### 14.08
```tsx
function JoinForm({submit}:{submit:(name:string)=>Promise<void>}){
  const [name,setName]=React.useState(''),[busy,setBusy]=React.useState(false),[error,setError]=React.useState('');
  return <form onSubmit={async e=>{e.preventDefault();if(!name.trim()||busy)return;setBusy(true);setError('');try{await submit(name.trim());}catch(err){setError(String(err));}finally{setBusy(false);}}}><label>公会名称<input required value={name} onChange={e=>setName(e.target.value)}/></label><button disabled={busy}>{busy?'提交中':'提交'}</button>{error&&<p role="alert">{error}</p>}</form>;
}
```
结果：必填校验、提交中禁重复、失败提示；完整入驻字段与隐私文案需按业务规则补齐。

### 14.09
```html
<style>.gallery{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:12px}.gallery img{width:100%;height:auto;display:block}</style>
<div class="gallery"><img src="a.jpg" width="800" height="600" alt="示例一"><img src="b.jpg" width="600" height="900" alt="示例二"></div>
```
结果：不同宽高图片在网格中保持比例；宽高属性帮助预留空间。

### 14.10
```tsx
function Reversed({items}:{items:Array<{id:string;text:string}>}){
  return <ul>{[...items].reverse().map(item=><li key={item.id}>{item.text}</li>)}</ul>;
}
```
结果：视觉和 DOM 顺序都反转，原始 `items` 不变。

### 14.11
```tsx
type TreeNode={id:string;name:string;children?:TreeNode[]};
function Tree({nodes}:{nodes:TreeNode[]}){
  return <ul role="tree">{nodes.map(node=><li role="treeitem" key={node.id}>{node.name}{node.children?.length?<Tree nodes={node.children}/>:null}</li>)}</ul>;
}
```
结果：递归显示节点；完整树组件还需展开状态与箭头键导航。

### 14.12
```tsx
function Tabs({tabs}:{tabs:Array<{id:string;label:string;content:string}>}){
  const [active,setActive]=React.useState(tabs[0]?.id);
  return <><div role="tablist">{tabs.map(tab=><button role="tab" aria-selected={active===tab.id} key={tab.id} onClick={()=>setActive(tab.id)}>{tab.label}</button>)}</div>{tabs.map(tab=>active===tab.id?<div role="tabpanel" key={tab.id}>{tab.content}</div>:null)}</>;
}
```
结果：点击标签切换面板；完整无障碍模式需加焦点和方向键处理。

### 14.13
```tsx
function MoveList({items}:{items:string[]}){
  const [order,setOrder]=React.useState(items);
  function move(from:number,to:number){setOrder(old=>{const next=[...old];next.splice(to,0,...next.splice(from,1));return next;});}
  return <ul>{order.map((x,i)=><li key={x}>{x}<button disabled={i===0} onClick={()=>move(i,i-1)}>上移</button></li>)}</ul>;
}
```
结果：可用键盘操作的按钮重排列表；指针拖拽需再接 Pointer Events。

### 15.01
```html
<svg viewBox="0 0 120 120" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="75" aria-label="完成进度"><circle cx="60" cy="60" r="50" fill="none" stroke="#ddd" stroke-width="10"/><circle cx="60" cy="60" r="50" fill="none" stroke="#315ac7" stroke-width="10" stroke-dasharray="314.16" stroke-dashoffset="78.54" transform="rotate(-90 60 60)"/><text x="60" y="66" text-anchor="middle">75%</text></svg>
```
结果：绘制约 75% 的环形进度并提供可读文本。

### 16.01
```js
console.log('sync');
setTimeout(()=>console.log('task'),0);
Promise.resolve().then(()=>console.log('microtask'));
```
结果：依次输出 `sync`、`microtask`、`task`；浏览器是否在两个任务间绘制由宿主决定。

### 16.02
```js
async function work(items){
  for(let i=0;i<items.length;i+=100){items.slice(i,i+100).forEach(expensive);await new Promise(r=>setTimeout(r,0));}
}
```
结果：每处理 100 项后让出主线程，给输入和绘制机会；`expensive` 是项目实际工作函数。

### 16.03
```js
function makeCounter(){let count=0;return ()=>++count;}
const counter=makeCounter();console.log(counter(),counter());
```
结果：`1 2`；返回函数保留了创建处的 `count`，长生命周期引用可用 Heap Snapshot 排查。

### 16.04
```js
class Parent{greet(){return 'hi';}}
class Child extends Parent{}
const child=new Child();console.log(child.greet(),Object.getPrototypeOf(Child.prototype)===Parent.prototype);
```
结果：`hi true`，方法沿原型链找到。

### 16.05
```js
const owner={n:2,arrow:()=>this?.n,regular(){return this.n;}};
console.log(owner.regular(),owner.regular.call({n:3}));
```
结果：`2 3`；箭头函数的 `this` 取决于定义处环境，不因 `.call` 改变。

### 16.06
```js
// a.mjs: export let count=0; export function inc(){count++}
// b.mjs: import {count,inc} from './a.mjs'; inc(); console.log(count);
```
结果：ESM 的 `b.mjs` 输出 `1`，因为导入是实时绑定；CommonJS 模块需在 Node 环境另写 `require` 示例。

### 16.07
```js
performance.getEntriesByType('navigation').forEach(n=>console.log({dns:n.domainLookupEnd-n.domainLookupStart,connect:n.connectEnd-n.connectStart,response:n.responseEnd-n.responseStart}));
```
结果：输出当前导航的 DNS、连接、响应阶段耗时；缓存命中时某些阶段为 0。

### 16.08
```js
const box=document.querySelector('#box');
box.style.transform='translateX(20px)';
```
结果：元素平移；可在 DevTools Performance 面板观察是否只需合成，具体由浏览器实现决定。

### 16.09
```js
new PerformanceObserver(list=>{for(const entry of list.getEntries())console.log(entry.name,entry.duration);}).observe({type:'longtask',buffered:true});
```
结果：浏览器支持时输出长任务名称与耗时；内存泄漏另用 Heap Snapshot 查保留链。

### 16.10
```js
localStorage.setItem('theme','dark');
sessionStorage.setItem('draft','hello');
console.log(localStorage.getItem('theme'),sessionStorage.getItem('draft'));
```
结果：`dark hello`；大结构化数据改用 IndexedDB，服务端会话通常用安全 Cookie。

### 17.01
```ts
function label(value:unknown){if(typeof value==='string')return value.toUpperCase();return 'unknown';}
function assertNever(value:never):never{throw new Error(String(value));}
console.log(label('ok'));
```
结果：运行输出 `OK`；`unknown` 用前需收窄，`never` 用于不可能分支。

### 17.02
```ts
type Shape={kind:'circle';radius:number}|{kind:'square';side:number};
function area(shape:Shape){if(shape.kind==='circle')return Math.PI*shape.radius**2;return shape.side**2;}
console.log(area({kind:'square',side:3}));
```
结果：`9`；判别字段将类型收窄到方形分支。

### 17.03
```ts
type Result={kind:'ok';value:number}|{kind:'error';message:string};
function show(result:Result){switch(result.kind){case 'ok':return result.value;case 'error':return result.message;default:{const unreachable:never=result;return unreachable;}}}
```
结果：新增 `kind` 分支但未处理时，`never` 赋值产生编译错误。

### 17.04
```ts
type Return<F>=F extends (...args:any[])=>infer R?R:never;
function first<T extends {id:string}>(items:T[]):T|undefined{return items[0];}
type Value=Return<()=>number>; // number
```
结果：`first([{id:'a'}])` 返回该对象；缺少 `id` 的输入编译失败。

### 17.05
```ts
type MyPartial<T>={[K in keyof T]?:T[K]};
type MyPick<T,K extends keyof T>={[P in K]:T[P]};
type User={id:number;name:string};
const patch:MyPartial<User>={name:'Ada'};
const identity:MyPick<User,'id'>={id:1};
```
结果：两段声明可通过类型检查；未知键会报错。

### 17.06
```ts
interface User{ id:number }
interface User{ name:string } // 声明合并
type Id=number|string;
const user:User={id:1,name:'Ada'};
```
结果：`User` 同时要求 `id` 与 `name`；`type` 可表达联合类型。

### 17.07
```ts
type Load<T>={status:'loading'}|{status:'success';data:T}|{status:'error';error:Error};
const state:Load<number>={status:'success',data:3};
if(state.status==='success')console.log(state.data);
```
结果：输出 `3`；加载分支不能意外读取 `data`。

### 17.08
```json
{"scripts":{"build":"vite build","typecheck":"tsc --noEmit","verify":"npm run typecheck && npm run build"}}
```
结果：`verify` 先做完整类型检查，再构建；Vite 单独转译不等于类型检查。

### 18.01
```css
.cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,16rem),1fr));gap:1rem}
.card-actions{display:flex;align-items:center;gap:.5rem}
```
结果：卡片二维响应式排布，卡片内操作用单轴 Flex。

### 18.02
```html
<style>.container{display:flow-root}.float{float:left;width:40px;height:40px}</style>
<div class="container"><div class="float"></div>正文</div>
```
结果：容器高度包含内部浮动元素，并形成独立 BFC。

### 18.03
```html
<img src="hero.webp" width="1200" height="600" alt="展示图">
<div style="min-height:160px" aria-busy="true">加载中…</div>
```
结果：图片和异步区域预留空间，减少布局偏移。

### 18.04
```css
:root{color-scheme:light dark;--bg:#fff;--fg:#111}
@media(prefers-color-scheme:dark){:root{--bg:#111;--fg:#fff}}
:root[data-theme="light"]{--bg:#fff;--fg:#111;color-scheme:light}
:root[data-theme="dark"]{--bg:#111;--fg:#fff;color-scheme:dark}
body{background:var(--bg);color:var(--fg)}
```
结果：默认跟随系统；设置 `data-theme` 可覆盖系统偏好。

### 18.05
```html
<button id="open" onclick="dialog.showModal()">打开弹窗</button>
<dialog id="dialog" aria-labelledby="title"><h2 id="title">设置</h2><form method="dialog"><button>关闭</button></form></dialog>
```
结果：原生模态对话框支持 Escape 和焦点约束；复杂场景仍要确认关闭后焦点回到触发按钮。

### 18.06
```html
<button type="button" onclick="save()">保存</button>
<a href="/help">帮助</a>
```
结果：按钮和链接自带键盘与语义；`save` 为应用中的保存函数。

### 18.07
```html
<label for="email">邮箱</label><input id="email" type="email" aria-describedby="email-error" aria-invalid="true">
<p id="email-error" role="alert">请输入有效邮箱</p>
```
结果：输入与标签和错误文本关联；实际提交后还需聚焦错误位置。

### 18.08
```css
.page{container-type:inline-size}
.layout{display:grid;grid-template-columns:minmax(0,16rem) minmax(0,1fr);gap:1rem}
@container (max-width:40rem){.layout{grid-template-columns:1fr}}
```
结果：`.layout` 的父容器 `.page` 宽度小于 40rem 时改为单列。

### 19.01
```http
GET /app.abc123.js HTTP/1.1

HTTP/1.1 200 OK
Cache-Control: public, max-age=31536000, immutable
ETag: "abc123"
```
结果：新鲜期内可用本地强缓存；过期后带 `If-None-Match` 可协商得到 304。

### 19.02
```http
OPTIONS /api/data HTTP/1.1
Origin: https://app.example
Access-Control-Request-Method: POST

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example
Access-Control-Allow-Methods: POST
```
结果：浏览器在跨源非简单请求前预检，许可后才发实际 POST。

### 19.03
```js
const n=performance.getEntriesByType('navigation')[0];
console.log({dns:n.domainLookupEnd-n.domainLookupStart,tls:n.connectEnd-n.secureConnectionStart,ttfb:n.responseStart-n.requestStart});
```
结果：输出当前导航部分阶段耗时；复用连接或缓存时可能为 0。

### 19.04
```js
const response=await fetch('/api');
console.log(response.ok);
// DevTools Network 的 Protocol 列可查看 h2 / h3；JS fetch 语义通常不因此变化。
```
结果：输出请求是否成功；协议版本需在网络面板或服务端协商信息中确认。

### 19.05
```js
const stream=new EventSource('/events');stream.onmessage=e=>console.log(e.data);
const socket=new WebSocket('wss://example.com/ws');socket.onopen=()=>socket.send('ping');
```
结果：SSE 单向接收事件，WebSocket 可双向发送；普通 `fetch` 适合单次请求。

### 19.06
```js
let refreshPromise=null;
async function api(url,options={}){
  let response=await fetch(url,options);
  if(response.status!==401)return response;
  refreshPromise??=fetch('/auth/refresh',{method:'POST',credentials:'include'}).then(r=>{if(!r.ok)throw Error('refresh failed');}).finally(()=>{refreshPromise=null;});
  await refreshPromise;
  response=await fetch(url,options);return response;
}
```
结果：并发 401 共用一次刷新；重放非幂等请求前需确认请求体可重放和权限状态。

### 19.07
```js
const message='<img src=x onerror=alert(1)>';
document.querySelector('#message').textContent=message;
```
结果：页面显示字面文本，不执行 `onerror`；需要富文本时用受信任清洗器。

### 19.08
```http
Set-Cookie: session=opaque; HttpOnly; Secure; SameSite=Lax; Path=/
```
结果：脚本不能读取该 Cookie；仅经 HTTPS 发送，并限制部分跨站携带场景。

### 19.09
```js
// 服务端伪代码：有副作用请求校验 Origin 和 CSRF token。
if(req.method==='POST' && (req.headers.origin!==allowedOrigin || req.headers['x-csrf-token']!==session.csrfToken)){
  res.statusCode=403;res.end('Forbidden');
}
```
结果：不满足同源来源和有效 token 的提交返回 403；服务端仍需安全管理 token。

### 19.10
```js
async function uploadParts(file,uploadId,chunkSize=1024*1024){
  for(let start=0,index=0;start<file.size;start+=chunkSize,index++){
    const part=file.slice(start,start+chunkSize);
    const response=await fetch(`/upload/${uploadId}/${index}`,{method:'PUT',body:part});
    if(!response.ok)throw Error(`part ${index} failed`);
  }
}
```
结果：按索引顺序上传分片；断点续传需先查询服务器已收到的分片并校验最终文件。

### 20.01
```tsx
function Counter(){const [n,setN]=React.useState(0);console.log('render');return <button onClick={()=>setN(x=>x+1)}>{n}</button>;}
```
结果：点击安排重新 render 并在 commit 后更新按钮文字；开发 Strict Mode 可能多次调用 render。

### 20.02
```tsx
function Rows({items}:{items:Array<{id:string;text:string}>}){return <ul>{items.map(x=><li key={x.id}><input defaultValue={x.text}/></li>)}</ul>;}
```
结果：重排列表时输入状态跟随稳定 `id`，而非错误地跟随数组位置。

### 20.03
```tsx
function Ticker({id}:{id:string}){React.useEffect(()=>{const timer=setInterval(()=>console.log(id),1000);return()=>clearInterval(timer);},[id]);return null;}
```
结果：`id` 改变时清理旧计时器、建立新计时器，不继续输出旧 `id`。

### 20.04
```tsx
const Expensive=React.memo(function Expensive({items}:{items:number[]}){return <p>{items.reduce((a,b)=>a+b,0)}</p>;});
function Parent({items}:{items:number[]}){const sorted=React.useMemo(()=>[...items].sort((a,b)=>a-b),[items]);return <Expensive items={sorted}/>;}
```
结果：`items` 引用不变时复用排序结果并可能跳过子组件渲染；收益须用 Profiler 测量。

### 20.05
```tsx
function Search({items}:{items:string[]}){const [query,setQuery]=React.useState('');const deferred=React.useDeferredValue(query);return <><input value={query} onChange={e=>setQuery(e.target.value)}/><p>{items.filter(x=>x.includes(deferred)).length}</p></>;}
```
结果：输入值立即变化，较慢的结果统计可延后；`useTransition` 适合把指定状态更新标为非紧急。

### 20.06
```tsx
function Submit({send}:{send:()=>Promise<void>}){const [pending,setPending]=React.useState(false),[error,setError]=React.useState('');return <><button disabled={pending} onClick={async()=>{setPending(true);setError('');try{await send();}catch(e){setError(String(e));}finally{setPending(false);}}}>提交</button>{error&&<p role="alert">{error}</p>}</>;}
```
结果：提交期间按钮禁用，错误可见；乐观更新需在失败时回滚。

### 20.07
```tsx
function SaveForm(){const [state,action,pending]=React.useActionState<{saved:string|null},FormData>(async(_old,form)=>({saved:String(form.get('name')??'')}),{saved:null});return <form action={action}><input name="name"/><button disabled={pending}>保存</button><output>{state.saved??''}</output></form>;}
```
结果：提交后 `state.saved` 显示名称；`useFormStatus` 可在子组件读取状态，`useOptimistic` 可显示临时值。

### 20.08
```tsx
const Theme=React.createContext('light');
function App(){const [theme,setTheme]=React.useState('light');return <Theme.Provider value={theme}><button onClick={()=>setTheme('dark')}>切换</button><View/></Theme.Provider>;}
function View(){return <p>{React.useContext(Theme)}</p>;}
```
结果：点击后 `View` 显示 `dark`；局部状态仍由 `useState` 管理。

### 20.09
```tsx
function Measured(){const renderStart=performance.now();React.useEffect(()=>console.log('commit elapsed',performance.now()-renderStart));return <div>内容</div>;}
```
结果：输出近似渲染到 effect 的时间；正式比较需用 React Profiler 和相同交互样本。

### 20.10
```tsx
function useJson(url:string){const [state,setState]=React.useState<{data?:unknown;error?:string;loading:boolean}>({loading:true});React.useEffect(()=>{const c=new AbortController();setState({loading:true});fetch(url,{signal:c.signal}).then(r=>{if(!r.ok)throw Error(String(r.status));return r.json();}).then(data=>setState({data,loading:false})).catch(e=>{if(!c.signal.aborted)setState({error:String(e),loading:false});});return()=>c.abort();},[url]);return state;}
```
结果：URL 改变时取消旧请求，返回加载、成功或失败状态。

### 20.11
```tsx
function Total({prices}:{prices:number[]}){return <output>{prices.reduce((a,b)=>a+b,0)}</output>;}
```
结果：总价正确性来自计算本身；若项目启用 React Compiler，可用编译诊断与 Profiler 检查是否自动记忆化。

### 21.01
```vue
<script setup>
import {ref,reactive} from 'vue'
const count=ref(0),user=reactive({name:'Ada'})
</script>
<template><button @click="count++">{{count}} {{user.name}}</button></template>
```
结果：点击后 `count` 增加，模板自动更新。

### 21.02
```vue
<script setup>
import {ref,computed,watch} from 'vue'
const n=ref(1),double=computed(()=>n.value*2)
watch(n,(next,prev)=>console.log(prev,next))
</script>
<template><button @click="n++">{{double}}</button></template>
```
结果：初始显示 `2`，点击后显示 `4`，watch 输出 `1 2`。

### 21.03
```vue
<!-- Parent.vue -->
<Child :value="count" @change="count=$event" />
<!-- Child.vue: defineProps<{value:number}>(); const emit=defineEmits<{change:[value:number]}>() -->
```
结果：子组件发 `change` 后父组件更新 `count`；跨多层共享可用 provide/inject。

### 21.04
```vue
<script setup>
const model=defineModel<string>({default:''})
</script>
<template><input v-model="model" /></template>
```
结果：父组件 `<Child v-model="name"/>` 与子组件双向同步值。

### 21.05
```vue
<script setup>
import {ref,nextTick} from 'vue'
const n=ref(0)
async function update(){n.value++;await nextTick();console.log(document.querySelector('#n')?.textContent)}
</script>
<template><button @click="update">更新</button><span id="n">{{n}}</span></template>
```
结果：点击后日志为新的 DOM 文本 `1`。

### 21.06
```js
// 迁移时先检查依赖，再让新入口使用 Vue 3 createApp。
import {createApp} from 'vue';
import App from './App.vue';
createApp(App).mount('#app');
```
结果：Vue 3 应用挂载到 `#app`；实际迁移还需逐项处理插件和不兼容 API。

### 21.07
```vue
<script setup>
import {reactive,toRefs} from 'vue'
const state=reactive({count:0})
const {count}=toRefs(state)
</script>
<template><button @click="count++">{{count}}</button></template>
```
结果：解构后仍保留响应性，点击更新数字。

### 21.08
```vue
<template><ul><li v-for="item in items" :key="item.id"><input :value="item.name"></li></ul></template>
```
结果：按稳定 `id` 识别节点；重排时输入不应错绑到其他项。

### 22.01
```tsx
// Next.js App Router：静态公开页面可在构建时生成。
export default async function Page(){const posts=await fetch('https://example.com/posts').then(r=>r.json());return <ul>{posts.map((p:{id:string;title:string})=><li key={p.id}>{p.title}</li>)}</ul>;}
```
结果：页面在服务端生成 HTML；具体缓存/重验证由项目版本和配置决定。

### 22.02
```tsx
// app/page.tsx (Server Component)
import Counter from './Counter';
export default async function Page(){const data=await loadPublicData();return <><h1>{data.title}</h1><Counter/></>;}
// Counter.tsx 以 'use client' 开头并使用 useState。
```
结果：标题由服务端输出，计数交互只给客户端组件加载 JS。

### 22.03
```tsx
'use client';
function Clock(){const [now,setNow]=React.useState<string|null>(null);React.useEffect(()=>setNow(new Date().toISOString()),[]);return <time>{now??'加载时间…'}</time>;}
```
结果：首屏服务端和客户端都先显示占位文案，挂载后更新，避免时间造成 hydration mismatch。

### 22.04
```tsx
// Server Component 内读取服务端环境变量，不把 secret 传给客户端。
export default async function Page(){const data=await fetchPrivate(process.env.API_SECRET);return <ClientWidget title={data.publicTitle}/>;}
```
结果：客户端只收到 `publicTitle`；密钥不进入可序列化 props。

### 22.05
```tsx
import {Suspense} from 'react';
export default function Page(){return <><h1>文章</h1><Suspense fallback={<p>正文加载中…</p>}><SlowArticle/></Suspense></>;}
```
结果：标题和 fallback 可先返回，慢正文随后流式到达；`SlowArticle` 是异步服务端组件。

### 22.06
```tsx
async function userProfile(userId:string){return fetch(`/api/users/${encodeURIComponent(userId)}`,{cache:'no-store'}).then(r=>r.json());}
```
结果：个性化资料每次读取，不作为公开共享缓存；服务端仍须校验当前用户权限。

### 22.07
```tsx
export const metadata={title:'产品说明',description:'公开的产品介绍'};
export default function Page(){return <main><h1>产品说明</h1><p>可抓取的正文</p><ClientAction/></main>;}
```
结果：服务端 HTML 有标题与正文，`ClientAction` 承担交互。

### 22.08
```tsx
import {Suspense} from 'react';
async function getPublicPosts(){'use cache';const response=await fetch('https://example.com/posts');return response.json();}
async function PostList(){const posts=await getPublicPosts();return <ul>{posts.map((p:{id:string;title:string})=><li key={p.id}>{p.title}</li>)}</ul>;}
export default function Page(){return <Suspense fallback={<p>加载中…</p>}><PostList/></Suspense>;}
```
结果：公开帖子数据可缓存；真实缓存寿命与失效策略须按项目 Next.js 版本配置。

### 23.01
```js
new PerformanceObserver(list=>{for(const e of list.getEntries())console.log(e.name,e.value??e.duration);}).observe({type:'largest-contentful-paint',buffered:true});
```
结果：浏览器支持时输出 LCP 候选；INP、CLS 需采集对应指标并按真实用户分组统计。

### 23.02
```html
<link rel="preload" as="image" href="hero.webp">
<img src="hero.webp" width="1200" height="600" fetchpriority="high" alt="首页主图">
<script type="module" src="app.js"></script>
```
结果：主图更早请求且预留尺寸；收益需用同口径 LCP 和网络瀑布验证。

### 23.03
```js
function visibleRange(scrollTop,rowHeight,viewportHeight,total){const start=Math.max(0,Math.floor(scrollTop/rowHeight)-3);const end=Math.min(total,Math.ceil((scrollTop+viewportHeight)/rowHeight)+3);return {start,end};}
console.log(visibleRange(500,50,300,1000));
```
结果：`{start:7,end:19}`；动态高度时要测量行高并维持滚动锚点。

### 23.04
```json
{"scripts":{"dev":"vite","build":"vite build","typecheck":"tsc --noEmit"}}
```
结果：开发走按需模块与 HMR，构建生成优化产物；类型检查需单独运行。

### 23.05
```js
const add=(a,b)=>a+b;
const unused=()=>42;
console.log(add(1,2));
```
结果：`3`；生产构建可能移除未调用的 `unused`，需检查实际产物确认。

### 23.06
```tsx
// Testing Library 示例：验证用户可见行为。
function Counter(){const [count,setCount]=React.useState(0);return <button onClick={()=>setCount(x=>x+1)}>{count}</button>;}
render(<Counter/>);
await user.click(screen.getByRole('button',{name:'增加'}));
expect(screen.getByRole('button',{name:'1'})).toBeVisible();
```
结果：点击后按钮显示 `1`；需在 Testing Library 测试环境运行。

### 23.07
```js
const controller=new AbortController();
const promise=fetch('/api',{signal:controller.signal});
controller.abort();
await expect(promise).rejects.toMatchObject({name:'AbortError'});
```
结果：测试验证取消分支；`expect` 需在 Vitest/Jest 环境中运行，网络请求应使用 mock。

### 23.08
```json
{"name":"@study/ui","private":true,"exports":{".":"./src/index.ts"},"peerDependencies":{"react":"^19"}}
```
结果：共享 UI 包只暴露指定入口，React 由使用方提供；版本范围需与实际工作区匹配。

### 23.09
```js
window.addEventListener('error',e=>report({message:e.message,release:APP_RELEASE}));
window.addEventListener('unhandledrejection',e=>report({message:String(e.reason),release:APP_RELEASE}));
```
结果：上报带版本的错误；`report` 须脱敏，Source Map 应受控上传，故障时回滚对应版本。

### 23.10
```js
const p75=values=>[...values].sort((a,b)=>a-b)[Math.ceil(values.length*.75)-1];
console.log(p75([100,200,300,400]));
```
结果：`300`；比较优化前后需同设备、同页面和同流量口径。

### 24.01
```js
async function readStream(response,onText){
  const reader=response.body.getReader(),decoder=new TextDecoder();
  try{while(true){const {done,value}=await reader.read();if(done)break;onText(decoder.decode(value,{stream:true}));}onText(decoder.decode());}
  finally{reader.releaseLock();}
}
```
结果：逐块得到解码文本；SSE 的 `data:` 边界还需跨块缓冲解析。

### 24.02
```js
const controller=new AbortController();
async function start(){try{const response=await fetch('/events',{signal:controller.signal});if(!response.ok)throw Error(String(response.status));await readStream(response,console.log);}catch(error){if(controller.signal.aborted)console.log('cancelled');else console.error('retryable error',error);}}
```
结果：用户取消显示 `cancelled`，网络失败进入重试状态；续传需服务器提供游标。

### 24.03
```js
const partialMarkdown='**未结束的流';
const preview=document.createElement('pre');
preview.textContent=partialMarkdown;
```
结果：流未结束时安全显示原始 Markdown 文本；最终富文本渲染需可信解析和 HTML 清洗。

### 24.04
```js
function shouldStick(container){return container.scrollHeight-container.scrollTop-container.clientHeight<80;}
const stick=shouldStick(chat);appendMessage(message);if(stick)requestAnimationFrame(()=>chat.scrollTop=chat.scrollHeight);
```
结果：用户原本接近底部时自动跟随；向上阅读历史时不抢滚动位置。

### 24.05
```js
let version=0,controller;
async function ask(prompt){const current=++version;controller?.abort();controller=new AbortController();const response=await fetch('/chat',{method:'POST',body:prompt,signal:controller.signal});if(current!==version)return;await readStream(response,text=>{if(current===version)append(text);});}
```
结果：新会话取消旧请求，旧流片段不会覆盖当前内容。

### 24.06
```tsx
function RunStatus({run,cancel}:{run:{state:'running'|'error'|'done';step?:string;error?:string};cancel:()=>void}){return <section aria-live="polite"><p>{run.state==='running'?`正在执行：${run.step}`:run.state==='error'?`失败：${run.error}`:'已完成'}</p>{run.state==='running'&&<button onClick={cancel}>取消</button>}</section>;}
```
结果：显示步骤、错误或完成状态；运行中可取消。

### 24.07
```js
// 对 AI 生成的纯函数先做可复现断言，再做依赖和安全审查。
const generated=(a,b)=>a+b;
console.assert(generated(0,0)===0);
console.assert(generated(-2,3)===1);
```
结果：两个边界断言通过；不能据此证明所有输入或外部依赖安全。

### 24.08
```js
// 工作流：保留输入、候选补丁、检查结果和人工审查结论。
const checks=['typecheck','unit','build'],results={typecheck:'passed',unit:'passed',build:'passed'};
console.log(checks.every(name=>results[name]==='passed'));
```
结果：`true`；真实 `results` 必须来自实际 CI，不可凭模型描述代替。

### 25.01
```js
let timer,controller,version=0;
function suggest(query){clearTimeout(timer);controller?.abort();const current=++version;timer=setTimeout(async()=>{controller=new AbortController();try{const r=await fetch(`/suggest?q=${encodeURIComponent(query)}`,{signal:controller.signal});if(current===version)render(await r.json());}catch(e){if(e.name!=='AbortError')showError(e);}},250);}
```
结果：防抖、取消和版本校验共同避免旧结果覆盖新输入；`render/showError` 为界面函数。

### 25.02
```js
// 服务端必须独立校验；前端权限只影响展示。
app.delete('/users/:id',authenticate,requirePermission('users:delete'),async(req,res)=>{await deleteUser(req.params.id);res.sendStatus(204);});
```
结果：无权限请求在服务端被拒绝；按钮隐藏不能替代接口鉴权。

### 25.03
```tsx
function SearchPage(){const [query,setQuery]=React.useState('');return <><SearchBox value={query} onChange={setQuery}/><SearchResults query={query}/></>;}
```
结果：只在最近共同父组件共享查询状态；跨页面共享再评估 Context 或状态库。

### 25.04
```js
const before={lcpP75:3200,inpP75:280},after={lcpP75:2400,inpP75:190};
console.log(before.lcpP75-after.lcpP75,before.inpP75-after.inpP75);
```
结果：样例改善 `800ms` 与 `90ms`；真实项目需填真实同口径数据并说明取舍。

### 25.05
```js
async function upload(file,id,onProgress){const chunk=1024*1024;for(let start=0,i=0;start<file.size;start+=chunk,i++){const response=await fetch(`/upload/${id}/${i}`,{method:'PUT',body:file.slice(start,start+chunk)});if(!response.ok)throw Error(`failed part ${i}`);onProgress(Math.min(file.size,start+chunk)/file.size);}}
```
结果：逐片上传并更新进度；服务端需要上传 id 幂等和最终校验。

### 25.06
```js
const byId=new Map();
function receive(message){byId.set(message.id,message);return [...byId.values()].sort((a,b)=>a.seq-b.seq);}
```
结果：按服务端序号展示且重复消息不会重复；断线时用最后序号请求缺失消息。

### 25.07
```js
const pending=new Map();let nextId=0;
function callNative(method,payload){if(!['openCamera'].includes(method))return Promise.reject(Error('denied'));const id=++nextId;return new Promise((resolve,reject)=>{const timer=setTimeout(()=>{pending.delete(id);reject(Error('timeout'));},5000);pending.set(id,{resolve,reject,timer});window.NativeBridge.postMessage(JSON.stringify({id,method,payload}));});}
```
结果：只允许白名单方法，5 秒无回执时拒绝；原生侧仍须校验来源和权限。

### 25.08
```js
// 线上白屏排查用版本与资源加载证据定位，回滚命令按实际平台执行。
window.addEventListener('error',e=>report({release:APP_RELEASE,url:e.filename,message:e.message}));
```
结果：错误事件携带发布版本和资源 URL；止损后检查部署、CDN、接口，再复盘根因。

### 26.01
```js
const page = {
  data: { selectedSku: 'A', quantity: 1 },
  setData(patch) { Object.assign(this.data, patch); console.log(JSON.stringify(patch)); }
};
const next = { selectedSku: 'A', quantity: 2 };
const patch = Object.fromEntries(
  Object.entries(next).filter(([key, value]) => page.data[key] !== value)
);
if (Object.keys(patch).length) page.setData(patch);
```
结果：只输出并更新 `{"quantity":2}`，避免把未变化的规格字段重复发送到视图层；真实优化仍需先测量。

### 26.02
```js
const cart = new Map();
const listeners = new Set();
const snapshot = () => [...cart].map(([skuId, quantity]) => ({ skuId, quantity }));
function setQuantity(skuId, quantity) {
  if (!Number.isInteger(quantity) || quantity < 0) throw Error('invalid quantity');
  if (quantity === 0) cart.delete(skuId); else cart.set(skuId, quantity);
  for (const listener of listeners) listener(snapshot());
}
listeners.add(items => console.log(JSON.stringify(items)));
setQuantity('ice-cream', 2);
```
结果：输出 `[{"skuId":"ice-cream","quantity":2}]`；多个页面可订阅同一购物车状态，结算价格仍须由服务端核算。

### 26.03
```js
const frames = [];
const requestFrame = callback => frames.push(callback); // 示例中手动推进一帧
const pendingChanges = new Map();
let scheduled = false;
function onStockMessage(message) {
  pendingChanges.set(message.id, message);
  if (scheduled) return;
  scheduled = true;
  requestFrame(() => {
    scheduled = false;
    const batch = [...pendingChanges.values()];
    pendingChanges.clear();
    console.log(JSON.stringify(batch));
  });
}
onStockMessage({ id: 1, stock: 9 });
onStockMessage({ id: 1, stock: 8 });
onStockMessage({ id: 2, stock: 3 });
frames.shift()();
```
结果：一帧只输出 `[{"id":1,"stock":8},{"id":2,"stock":3}]`；只适用于可用最新值覆盖旧值的状态消息，不可合并的订单事件必须逐条处理。

### 26.04
```js
function visibleRange(total, scrollTop, rowHeight, viewportHeight, overscan = 2) {
  const start = Math.max(0, Math.floor(scrollTop / rowHeight) - overscan);
  const end = Math.min(total, Math.ceil((scrollTop + viewportHeight) / rowHeight) + overscan);
  return { start, end }; // end 为不包含的边界
}
const { start, end } = visibleRange(10000, 400, 40, 120);
console.log(`${start}..${end - 1} 共${end - start}条`);
```
结果：输出 `8..14 共7条`，只渲染这 7 条；动态行高需测量并维护位置索引，不能直接使用固定行高公式。

