面经题库满天飞,每道题后面都跟着一份「标准答案」。
问题是:这些答案是谁写的?什么时候写的?有没有人真的跑过?
我挑了流传最广的 10 道前端题,每道先找到真实题库里的答案原文(出处登记在实验档案里),再拿 Node 24 和真浏览器跑一遍,官方文档做仲裁。判分规则跑前定死:A = 照背会答错;B = 能蒙混但被追问就露怯;C = 完全正确。
结果先放这儿------
| # | 题目 | 流传答案 | 判分 | 实测真相 |
|---|---|---|---|---|
| 1 | localStorage 能存多少 | 5MB | A 错 | 实测能存 5,222,400 个字符,ASCII 内容约 10MB |
| 2 | JS 数据类型几种 | 6 种 | B 过时 | 现在是 7 原始 + object = 8 种,漏了 ES2020 的 bigint |
| 3 | Object.assign 深浅拷贝 | 一级属性时是深拷贝 | A 错 | 永远浅拷贝,改嵌套属性两边同步变 |
| 4 | JSON 法做深拷贝 | 最简单的深拷贝方案 | B 不完整 | Date 变字符串、undefined 丢失、循环引用直接抛错 |
| 5 | let 有没有提升 | 没有提升 | A 错 | 报错文案恰恰证明提升过,只是不让碰 |
| 6 | const 值不可变 | 值不能改变 | B 片面 | 锁的是绑定不锁值,obj.a = 2 不报错 |
| 7 | setTimeout(fn, 0) | 尽快执行(没人再讲) | B 不完整 | 嵌套到第 7 层被硬钳到 4ms,实测 [0,0,0,0,0,0,5,5] |
| 8 | GET 长度限制 | 2048 字符 / 2KB | A 错 | Chrome 实测 1MB URL 照发 200,2048 是 IE 遗物 |
| 9 | Promise.all 一个失败 | 终止后续处理 | A 错 | 其余 4 个请求照样跑完,只是结果被丢弃 |
| 10 | 每域名 cookie 上限 | 20 个 | A 错 | Chrome 实测 ~180 个,RFC 最低要求 50,差 9 倍 |
10 道题,6 道 A,4 道 B,0 道 C。
没有一道流传答案完全站得住。下面按杀伤力排序,逐道说。
localStorage:5MB 背了十年,单位就是错的
题库原文(博客园、CSDN、腾讯云、掘金、牛客五家同款):「存储容量是 5MB」。
我在 Chrome 里写了个循环,往 localStorage 一直塞数据,直到抛 QuotaExceededError:
vbnet
storedChars: 5222400 // 51 个 100KB 块,然后炸了
err: "QuotaExceededError: ... exceeded the quota."
5,222,400 个字符。MDN 原文:「The keys and the values stored with localStorage are in the UTF-16 string format」------配额按字符数算,不按字节算。
5M 个字符装 ASCII 内容,磁盘上就是 10MB。规范里的建议值是 5 MiB per origin,按 UTF-16 code unit 计数------「5M 个字符」传着传着变成了「5MB」。
判决:错。 差一倍,单位级错误。面试官追问一句「那存 4M 个汉字呢?」背 5MB 的人当场哑火------汉字也是一字符一个 code unit,照样 5M 个,但很多人以为汉字要按 2 字节折半算。
cookie 20 个上限:这答案是 2010 年的
牛客《前端面试经典题目合集》开头第一句:「每个特定的域名下最多生成20个cookie」。掘金 30K 合集、知乎 32000 字总结、腾讯云 42 道 HTML5------同一句,一字不差,复制了十年。
原文里其实有线索:「IE6或更低版本最多20个cookie」。20 是 IE6 的数。
现在的真值:RFC 6265 要求浏览器每域至少支持 50 个;Chromium 源码里写死常量 kDomainMaxCookies = 180。我实测同域连写 300 个 cookie,Chrome 留下 176 个------超了就静默把最旧的挤掉,连个警告都没有。
makefile
attempted: 300
kept: 176 // q0~q92 已被静默逐出
判决:错。 背 20 的人去真机上写第 21 个 cookie,毫无反应,简历就写在这了。
let 不提升?报错文案第一个不服
题库齐声:「var 存在变量提升,let 和 const 不存在变量提升」(腾讯云秋招合集、掘金、博客园三家同款)。
跑一下:
js
try {
void x; // let x 声明在后面
} catch (e) {
console.log(e.message);
}
// Cannot access 'x' before initialization
看清楚报错文案:「不能在初始化之前访问」。不是「x is not defined」。
引擎认得这个变量------绑定已经建立了,只是初始化前不让你碰,这段区域叫暂时性死区(TDZ)。报错本身就是提升的证据。 如果 let 真的不提升,报错应该和访问一个从未声明的变量一模一样。
对照组 var:声明前访问返回 undefined,不报错------那才叫「提升且可直接访问」。
判决:错。 背「不提升」的人,第二轮被问「那为什么报错文案不是 is not defined」,就交代了。
Promise.all 不会「终止」任何请求
这道题我专门找了个新鲜的错法------CSDN 今年 4 月的文章,原话:「只要有任意一个失败,就会立即返回失败结果并终止后续处理」。
跑一遍就露馅:
js
let started = 0, finished = 0;
const job = (ms) => new Promise((res, rej) => {
started++; // 请求发出,同步计数
ms === 0 ? rej(new Error('boom'))
: setTimeout(() => { finished++; res(1); }, ms);
});
Promise.all([job(0), job(40), job(40), job(40), job(40)]).catch(() => {});
setTimeout(() => console.log(started, finished), 120);
// 5 4 ← reject 之后,其余 4 个照样跑完了
5 个任务全部发出,1 个失败后 40ms,剩下 4 个全部完成。Promise.all 拒绝得再快,也追不回已经发出去的请求------它只是把结果扔了,不做取消。想真取消,得 AbortController。
判决:错。 「终止后续处理」四个字,把「Promise.all 拒绝」和「请求被取消」混成了一件事。面试官就爱在这里下钩子。
GET 2048 字符:协议没这条,IE 才有
「URL最大长度是2048个字符」------腾讯云测试题库、知乎每日一题、CSDN 面试题三家同款,很多还加一句「HTTP 协议规定」。
RFC 9112 的原文:「HTTP does not place a predefined limit on the length of a request-line」。协议没规定过任何长度限制。
真机实测,用一台不限长的本地服务器接 Chrome 发出的 GET:
16KB → 200 512KB → 200
64KB → 200 1MB → 200
2MB → Chrome 拒发(客户端上限)
1MB 的 GET 照发不误。而同一台机器上,Python 自带的测试服务器 64KB 就回 414,Nginx 默认 8KB 就嫌长------每个实现都有自己的口味,数字全不一样,唯独 2048 不属于任何一家现在的主流。它是 IE 时代的遗物。
判决:错。 「协议规定 2KB」这句话本身就是扣分项。正确姿势:协议无限制,浏览器和服务器各有限制,Chrome 客户端大约 2MB,具体数字查你目标服务的文档。
Object.assign:什么「一级属性是深拷贝」,它永远是浅拷贝
博客园和 CSDN 两家题库同文案:「当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候......浅拷贝」。
这话乍一听有道理,其实是把「看起来像」说成了「是」。对象没有嵌套属性时,浅拷贝和深拷贝根本没有区别可以观察------因为没有引用可共享。这不叫「变成了深拷贝」,这叫没得考。
MDN 写得明明白白:「Object.assign() 只复制属性值......假如源对象是一个对象的引用,它仅仅会复制其引用值」。分类上,它自始至终是浅拷贝。
判决:错。 题库作者想帮人理解「拷贝深度」的直觉,结果造出了一个错误分类。照这个说法答题,面试官基本可以断定你没读过文档。
JSON 法深拷贝:能过初面,上生产就翻车
「深拷贝用 JSON.parse(JSON.stringify()) 就行」------题库把它当最简方案讲,大多数不讲代价。
我数了一下它到底丢什么:
js
const cp = JSON.parse(JSON.stringify({
d: new Date(), // "1970-01-01T00:00:00.000Z" Date 变字符串
u: undefined, // 字段直接没了
nan: NaN, // null
inf: Infinity, // null
re: /x/g, // {}
m: new Map(), // {}
s: new Set(), // {}
}));
// 循环引用 → TypeError: Converting circular structure to JSON
七宗罪,全是真机跑出来的。生产代码该用 structuredClone()------浏览器和 Node 18+ 都有,这些坑一个不踩。(JSON.stringify 本身的坑我上个月写过一篇七坑专测,这里只算深拷贝这一仗。)
判决:B。 说它是「最简单方案」没错,题库错在只字不提代价。背了它的人写埋点代码丢 undefined 字段,查一天查不出来。
「6 种数据类型」------你的题库停在 2019
「js 一共有六种基本数据类型......还有在 ES6 中新增的 Symbol」------CSDN、segmentfault、知乎三家的答案几乎逐字相同。
Symbol 时代这答案是对的。但 2020 年 ES2020 加了 bigint,跑一下:
js
typeof 10n // 'bigint'
现在的正确答案:7 种原始类型(number、string、boolean、undefined、null、symbol、bigint)+ object = 8 种。
判决:过时。 数据类型是开场第一题,答「6 种」,面试官在心里给你贴的标签是「知识没更新过」------后面每道题都会往坏了猜。
const:锁的是绑定,不是值
面试库原话:「const 声明一个只读的常量。一旦声明,常量的值就不能改变。」------不提对象。
跑一下:
js
const obj = { a: 1 };
obj.a = 2; // 不报错,obj.a === 2
obj.a = 3; // 照样不报错
const z = 1;
z = 2; // TypeError: Assignment to constant variable
const 锁的是变量名到值的绑定 ,不是值本身。原始类型值不可变所以看起来像「常量」,对象类型的属性随便改。想真冻结,Object.freeze()。
判决:片面。 背原话的人遇到 const arr = []; arr.push(1) 会犹豫,犹豫就是破绽。
setTimeout(fn, 0):题库只对了一半
这一道例外------题库普遍教的是「不是立即执行」,对的。但全部止步于此,没一个人讲下一个问题:那最快多久?
我实测了嵌套定时器的延迟曲线:
嵌套层级 1~6 层:实际延迟 0ms
嵌套层级 7、8 层:实际延迟 5ms
HTML 规范写死了:嵌套超过 5 层,定时器最小间隔强制 4ms。这就是为什么 [0,0,0,0,0,0,5,5]------前 6 层随便快,第 7 层起被浏览器硬踩了刹车(防嵌套定时器饿死页面)。
判决:不完整。 「0 毫秒是尽快调度」这个答案能过初面;追问「嵌套呢?最小延迟多少?」就没了。面试拉开差距的从来是这半句。
为什么标准答案会集体错
复盘这 10 道题,错误来源就三个:
化石层。localStorage 5MB、cookie 20 个、GET 2048------全是 IE 时代的事实,被抄进了题库,抄了十年没人验。原文里明明写着「IE6」,抄的人只抄结论不抄条件。
没跑过代码。let 提升、Promise.all、Object.assign 这三道,答案作者只要真跑过一次就知道自己写错了。题库是抄写的产物,不是实验的产物。
传话丢限定词。「5 MiB per origin(按 code unit 计)」传成「5MB」;「IE6 最多 20 个」传成「每域 20 个」;「协议没有限制,实现有」传成「协议限制 2KB」。每转一手,限定词掉一层。
面试官为什么爱追问?因为第一轮听的是答案,第二轮听的是边界。背题库的人第一轮全对,第二轮全军覆没------这次 10 道 0 全对就是证据。
实验边界,先说清楚
单机单浏览器(Node 24.14.1 + 本机 Chrome),数字随版本可能浮动,方法比数值可靠;题库抽样 10 道,不是全量普查;「流传答案」以能检索到的真实题库页面为准,每道都留了出处,实验档案和 Node 脚本可复跑。
轮到你了
这 10 道是覆盖率最高的题,错得最整齐的题。冷门题库里的错误只会更多。
评论区报一个:你背过的哪个「标准答案」,后来发现是错的? 我攒一波,下篇做续集------专挑评论区踩过坑的题,继续真机验证。