1. 写在前面:为什么这份2019年的卷子至今值得翻
前端校招笔试,京东这份2019年的卷子,在我印象里属于“题型全、难度中上、兼顾基础与实战”的典型代表。虽然每年题目都在变,但前端考察的底层能力模型——JavaScript基础、浏览器原理、网络协议、框架理解、代码实战——基本是稳定的。这也是我把这份老题反复拿出来分析的原因:它考察的很多点,放到今天依然是面试必问内容,甚至在某些维度上比现在一些公司的题目更有区分度。
这份卷子适合谁看?一是正在准备校招的应届生,可以通过它了解大厂笔试的出题风格和踩分点;二是工作一两年的前端,可以用它查漏补缺,检验自己的基础是否扎实;三是带新人的同学,可以直接把里面的题目当作业题用。文章里我尽量把每一道有代表性的题目拆开讲清楚考点、思路和容易踩的坑,而不是只贴答案。
先提醒一句:网上流传的“京东2019校招前端笔试题”版本很多,题目序号并不完全一致,但核心考点是大同小异的。我这里以最能代表京东出题风格的版本为主,结合我自己的刷题和实际面试经验来做解析。
2. 整体出题思路拆解:京东到底想筛什么样的人
2.1 题型分布与分值逻辑
京东2019前端笔试题的构成大致分成四个模块:单选、多选、编程题、简答题。单选和多选覆盖的面非常广,从HTML标签语义、CSS布局、JavaScript语法,到浏览器缓存、跨域、前端安全,几乎每个前端知识板块都会涉及到。编程题一般是两道左右,考察代码实现能力;简答题则偏向场景设计,比如性能优化方案、组件设计思路这类开放性问题。
这个结构在今天的校招笔试里依然很主流。它的潜台词是:先通过客观题快速过滤基础不牢的人,再用编程题筛掉“只会背概念不会写代码”的人,最后用开放题看候选人的思路和知识广度。很多同学容易犯的错是在单选多选上花太多时间纠结,结果编程题来不及写。我后面会详细说时间分配的问题。
2.2 考点权重:基本功占七成,框架只做浅层考察
把京东这份卷子的考点拉一个清单,你会发现一个很明显的规律:JavaScript核心语法和浏览器原理相关的题目占了大概百分之六七十,HTML/CSS占百分之二十左右,框架相关内容占比并不高,而且考察得比较浅,一般就是响应式原理、生命周期这类概念题。
这不是京东一家的情况,早期校招笔试普遍如此。原因很简单:校招候选人没有太多项目经验背书,面试官能依赖的只有基础能力来判断潜力。框架年年换,但JavaScript的语言特性和浏览器的运行机制是相对稳定的,把这类基础考扎实了,候选人学什么框架都快。所以在备考京东这类大厂笔试时,重基础、轻框架是核心策略。
2.3 时间分配:从卷面倒推答题节奏
京东这份卷子题量不小,尤其多选题很耗时间。我的经验是拿到卷子先花一两分钟快速浏览全部题目,把编程题和简答题的位置找出来,心里有个底。客观题部分尽量控制在35分钟内完成,不会的题目先标记跳过,不要恋战。
多选题是重灾区,因为少选、错选都不得分的设定非常严格。做多选的策略是逐项独立判断,不要因为觉得“选项A和B好像有点像,可能都是对的”就草率全选。编程题至少要留出20到25分钟,如果前面客观题超时了,编程题只会写一半,那笔试大概率就挂了。后面第5章我会详细讲编程题的常见题型和答题套路。
3. JavaScript核心考点逐题拆解
3.1 变量提升与暂时性死区:基础中的拉分题
几乎每一份前端笔试题都会有一道变量提升相关的题目,京东也不例外。典型的考法是这样的:
console.log(a); // ? var a = 10; console.log(b); // ? let b = 20;第一行的输出是undefined,因为var声明的变量会提升到作用域顶部,但赋值不会跟着提升,所以此时a是undefined。第二行代码则会直接报错,提示Cannot access 'b' before initialization,这就是let/const的暂时性死区特性:变量在声明之前不能使用,连undefined都没有,直接是运行时错误。
这个知识点本身不难,但很多同学会在复杂场景下翻车,比如在if块里用var声明变量,或者混淆了函数声明和函数表达式的差异。函数声明是会整体提升的,函数表达式只有变量名提升。京东这类题目往往会增加一个弯,比如在块级作用域内部声明函数再在外部调用。记住一个原则:var看函数作用域,let/const看块级作用域,函数声明整体提升优于变量声明。
3.2 this指向:四句话记住所有场景
this指向问题在京东笔试里几乎必考,而且会以选择题和判断题的混合形式出现。我的记忆方法是四句话:普通函数调用this指向window(严格模式下是undefined);对象方法调用this指向该对象;构造函数调用this指向新生成的对象;箭头函数没有自己的this,沿用外部作用域的this。
实际考题里最阴险的是把多个规则叠加在一起。比如这个经典场景:
var name = 'global'; var obj = { name: 'obj', getName: function() { return function() { return this.name; }; } }; console.log(obj.getName()()); // ?答案是'global',因为返回的匿名函数是普通函数调用,this指向window。如果改成箭头函数,那this就会沿用getName方法的this,指向obj。这类嵌套函数加箭头函数的组合是拉分点,建议多刷几道代表性题目。
3.3 闭包与内存:既要会做题,也要会聊
闭包的考察在笔试题里通常有两种角度。第一种是直接让你判断代码输出,比如经典的循环加定时器:
for (var i = 0; i < 5; i++) { setTimeout(function() { console.log(i); }, 1000); }输出是五个5,因为var没有块级作用域,循环结束后i已经变成5,五个定时器回调共享同一个i。解法有两个:把var改成let,或者用闭包包一层(IIFE)传入当前的值。
第二种考法是让你讲讲闭包的“作用”,这种通常在简答题里出现。闭包的价值在于可以创建私有变量,模拟模块化的封装;缺点是变量长期驻留在内存中,如果大量使用且不主动释放,会出现内存泄漏。我在实际工作中见过不少因为滥用闭包导致页面越来越卡的案例,笔试里能把这个两面性讲清楚,得分会高不少。
3.4 Promise与async/await:异步流程控制的必考点
京东笔试题里Promise的考察频率相当高,常见形式是判断输出顺序。比如:
async function test() { console.log(1); await Promise.resolve(); console.log(2); } console.log(3); test(); console.log(4);这段代码的输出顺序是3、1、4、2还是1、3、4、2?答案是3、1、4、2。因为test()调用后,同步执行console.log(1),遇到await会先把后面的逻辑挂起,让出执行权,先执行后面的同步代码console.log(4),等同步代码执行完,微任务队列里的console.log(2)才会执行。
这个考点背后是事件循环机制。我的建议是把宏任务、微任务、渲染时机这三者的关系彻底搞懂,不要死记输出结果。理解了微任务在同步代码结束后、下一个宏任务开始前执行这个原则,遇到再复杂的输出题都能推出来。京东的题目通常会把setTimeout、Promise、process.nextTick(Node环境)混在一起考,只要抓住了队列优先级(process.nextTick大于Promise微任务)就不会乱。
4. 浏览器原理与网络基础:问答式考点的高发区
4.1 从URL输入到页面渲染:一道题覆盖整条知识链
京东笔试的简答题里,让描述“浏览器输入URL回车后发生了什么”是出现频率极高的题目。这题看似老套,但能考察的知识面非常广:DNS解析、TCP连接、HTTP请求、服务器响应、浏览器解析HTML/CSS/JS、渲染树构建、布局绘制、资源加载优化等,每个环节都可以延伸出一堆细节。
答这题的关键是分层清晰,不要一团浆糊地从头说到尾。我建议按这个顺序回答:DNS解析获取IP地址;建立TCP连接(如果要聊深一点,可以提三次握手和TLS协商);发出HTTP请求,服务器返回HTML;浏览器按HTML、CSS、JavaScript的顺序解析资源;解析过程中遇到外部资源会并发下载;构建DOM树和CSSOM树,合成渲染树;布局计算位置,然后由合成器完成绘制。说完这个主干,如果还有余力,可以聊一聊重排和重绘的区别、如何用will-change做合成层优化等加分项。
4.2 缓存机制:强缓存与协商缓存的关系网
浏览器缓存是网络类题目里的必考点,京东经常会以选择题形式考察Cache-Control和ETag的关系。核心框架是:浏览器请求资源时,先检查强缓存,如果命中(比如Cache-Control: max-age=3600且没有过期)就直接用本地缓存,不发出请求;如果强缓存未命中,则带着If-Modified-Since或If-None-Match去询问服务器,由服务器判断是否返回304,这就是协商缓存。
很多同学容易混淆的点是:Expires是HTTP/1.0的产物,存在客户端与服务器时间不一致的问题;Cache-Control是HTTP/1.1的标准,用相对时间,优先级更高。而ETag比Last-Modified更精确,因为时间戳只能精确到秒,文件在同一秒内修改但内容变化时,Last-Modified会漏判。京东笔试很喜欢把这些细节设置成干扰项,做题时一定要看清选项描述里的限定词。
4.3 跨域方案对比:不只背方案,还要知道取舍
跨域的考察一般会以“有哪些解决方案”的形式出现,要求你写三四种出来。最基本的要能写出JSONP、CORS、postMessage、document.domain,其中CORS是主流方案,需要理解简单请求和预检请求的区别。简单请求满足两个条件:方法是GET/HEAD/POST,且Content-Type是application/x-www-form-urlencoded、multipart/form-data、text/plain之一,否则会先发出OPTIONS预检请求。
我在实际项目里遇到过的问题是,很多同学知道CORS可以加Access-Control-Allow-Origin,但不知道如何应对携带Cookie的情况。这时需要前后端配合:前端设置credentials: 'include',后端设置Access-Control-Allow-Credentials: true,注意Access-Control-Allow-Origin此时不能是*,必须是具体域名。笔试题里如果考察这个细节,能写出来的人很少,属于拉开差距的加分点。
4.4 前端安全:XSS和CSRF的区分
京东笔试题对XSS和CSRF的考察通常是概念辨析加防御方案。XSS是攻击者在页面注入恶意脚本,核心危害是窃取用户数据、篡改页面;防御手段包括对用户输入进行转义、使用CSP(内容安全策略)、对Cookie设置HttpOnly属性。CSRF是攻击者诱导用户向已认证的网站发送请求,防御手段是校验Origin/Referer、使用CSRF Token、设置SameSite Cookie属性。
这里容易混淆的点在于:XSS攻击的是用户与网站的信任关系,CSRF攻击的是网站对用户浏览器的信任关系。笔试中如果出场景判断题,先判断攻击类型属于注入还是伪造请求,再针对性地给出方案,基本就能拿分。我在面试中经常会追问一句“如果你已经上线了一个CSRF漏洞,你最先做什么”,此时最快的止损措施是加Token校验,其次是收紧Cookie的SameSite属性。
4.5 存储方案选型:Cookie、localStorage、sessionStorage、IndexedDB
存储选择题看起来基础,但京东会出一些边界条件来考察理解深度。四个选项的区分点是:Cookie约4KB,每次请求都会自动携带在请求头里,可设置过期时间;localStorage约5MB,持久保存,不随请求发送;sessionStorage是标签页级别,关闭标签页即清除;IndexedDB是浏览器内置的NoSQL数据库,适合存结构化数据和大量数据。
一个非常典型的考法是问“如果要在浏览器端存储用户购物车数据,且需要跨标签页同步,你会选什么”。答案通常是localStorage配合storage事件监听,或者用IndexedDB配合BroadcastChannel。能结合场景说出选型依据,而不是只背大小和生命周期,才是这道题真正想考察的东西。
5. HTML/CSS布局与选择器:容易被忽视的送分题
5.1 盒模型与BFC:每个前端都该闭嘴背出的内容
盒模型在笔试题里出现的概率接近百分之百。京东考过一道典型的题:box-sizing: content-box和border-box的区别是什么?content-box下,width只包含内容区,实际占用的宽度是width + padding + border;border-box下,width包含内容、内边距和边框,实际占用宽度就是width。项目里我几乎无脑用border-box,因为它更符合直觉,也方便做栅格布局。
BFC(块级格式化上下文)则是CSS高频考点,表现形式是一个独立的渲染区域,浮动元素不会影响BFC内部之外的布局。触发BFC的方式包括:float不为none、overflow不为visible、display为inline-block/flex/grid等、position为absolute/fixed。京东的考题经常会给出一个父元素高度塌陷的场景,让你选解决方案,知道可以用overflow: hidden触发BFC来清除浮动影响,这道题就能拿下。
5.2 布局题:flex和grid是万能钥匙
京东笔试的布局题一般不会让你手写全套代码,更多是给出某段CSS,让你判断布局结果。Flex布局最常考的点是flex: 1的含义,它其实是flex: 1 1 0%的简写,表示项目会按比例占用剩余空间。而align-items和justify-content的方向区分是另一个易错点——前者控制交叉轴,后者控制主轴,主轴方向由flex-direction决定,不能死记“横向居中”这类结论。
Grid布局在笔试里出现频率略低,但京东也考过grid-template-columns: repeat(auto-fill, minmax(100px, 1fr))这样的代码意图。这道题其实是在考察响应式栅格的自适应能力,auto-fill会在容器宽度允许时自动放置尽可能多的列,而minmax(100px, 1fr)保证列的最小宽度是100px,超过后平均分配剩余空间。能看懂这种一行代码的响应式写法,说明你真正用过Grid,而不只是背了属性名。
5.3 圣杯布局与双飞翼布局:回归传统经典
虽然Flex和Grid已经非常成熟,但京东这份卷子里依然出现了传统布局方式。原因在于,理解浮动布局的演化过程,有助于理解现代布局解决的问题。圣杯布局是左右两栏固定宽度、中间自适应,双飞翼布局是它的改进版,区别在于中间的DOM结构和内容保护方式。
如果考试时间紧张,我不建议在这一类题上花太多时间抠细节,但至少要明白它们要解决的问题和核心实现思路:用负边距把左右浮动栏拉到正确位置,中间栏需要设置左右padding或margin来避免内容被遮挡。实测下来,能用flex三行代码解决的问题,就不要手写浮动版,但在回答“为什么会有这种布局”时,能讲出历史背景会显得基础扎实。
6. 实现类编程题:把思路写成代码的关键
6.1 高频手写题:防抖、节流、深拷贝
编程题是京东笔试的拿分大头。手写防抖和节流几乎是标配。防抖的核心是:事件触发后设置一个定时器,在等待时间内如果再次触发,就清除上一次的定时器重新开始计时;节流的核心是:保证一定时间间隔内只执行一次函数。我在手写时建议用闭包保存定时器状态,并处理好this指向和参数透传:
function debounce(fn, wait) { let timer = null; return function(...args) { const context = this; clearTimeout(timer); timer = setTimeout(() => { fn.apply(context, args); }, wait); }; } function throttle(fn, interval) { let lastTime = 0; return function(...args) { const context = this; const now = Date.now(); if (now - lastTime >= interval) { fn.apply(context, args); lastTime = now; } }; }深拷贝是另一个高频手写题。要拿满分,需要兼顾数组、普通对象、Date、RegExp等类型,并且处理循环引用。只用JSON.parse(JSON.stringify())的答案在笔试里只能得一半分,因为它会丢失函数、undefined、Symbol,而且遇到循环引用会直接报错。我建议记一个递归版本的深拷贝模板,面试时能三两分钟写完,笔试也能拿全分。
6.2 数组与字符串题目:考的是API熟练度和优化意识
京东的编程题会有一道偏算法或偏数据处理的题目,通常是数组去重、数组扁平化、字符串翻转这类基础操作。数组去重的解法有很多种,笔试时最好先写出最直观的ES6 Set解法,再补充一个filter + indexOf或者哈希表的解法,展示你有优化意识。
数组扁平化也是高频题。如果只要求拍平一层,Array.prototype.flat(n)最直接;如果要求完全拍平,需要递归或reduce加递归组合。我在准备这类题目时的经验是:不是为了应付笔试而刷题,而是要弄懂每种方法的适用边界。比如flat(Infinity)虽然能完全拍平,但在某些老环境里不支持,这时递归实现就派上了用场。
6.3 手写Promise.all:进阶题的典型代表
京东笔试的编程题有可能出现手写Promise.all这类题目,它的难度比防抖节流高一个档次,但原理并不复杂:接收一个Promise数组,返回一个新的Promise,当所有Promise都成功时,把所有结果按顺序组成数组返回;一旦有一个失败,就立刻reject。
function promiseAll(promises) { return new Promise((resolve, reject) => { if (!Array.isArray(promises)) { return reject(new TypeError('arguments must be an array')); } const results = []; let count = 0; const len = promises.length; if (len === 0) return resolve([]); promises.forEach((p, index) => { Promise.resolve(p).then( (value) => { results[index] = value; count++; if (count === len) { resolve(results); } }, (error) => { reject(error); } ); }); }); }这里的关键点是:结果数组要按下标顺序存放,而不是按完成时间,因为Promise的完成顺序不一定是传入顺序。另外,用Promise.resolve(p)包一层可以处理传入非Promise值的情况。笔试时能写出这几个细节,说明你是真懂Promise的,不是背模板。
7. 京东风向标:从特色题看大厂偏好
7.1 开放题:不止考察代码,还考察业务思维
京东笔试题里偶尔会出现一些“设计一个xx页面”或者“如何优化xx场景”的开放题,比如让设计一个商品列表页的加载方案,或者优化一个移动端页面的首屏速度。这种题目没有标准答案,但判卷者心里有一个得分区间。
回答开放题的方法是分层作答:先说总体思路,再按资源加载、渲染性能、交互体验等维度展开。举个例子,如果问题是“优化商品列表页首屏速度”,可以从这几个角度拆:首屏只请求需要的接口数据,图片做懒加载,关键CSS内联,JS按路由拆分打包,服务端配置CDN和缓存策略。能说出两三个有深度的优化手段并不难,难的是把措施和效果绑定在一起,让面试官感受到你有项目经验,而不是背了一堆专业名词。
7.2 细节陷阱:从题干文字里找坑
京东笔试题有一个风格特点,就是题干里会埋一些细节陷阱。比如同样考察闭包,它会写“使用var声明的变量在for循环中配合setTimeout”,如果你平时只看答案没亲自跑过代码,很容易选错。再比如CSS里position: sticky的生效条件,题干会特意提及父级元素的overflow属性会影响sticky效果。
我的建议是,平时刷题不要只满足于“这道题我会”,要把每一个选项为什么错、为什么对都搞清楚。笔试时先看题干最后一句问的是“正确的是”还是“错误的是”,这种低级的审题错误每年都有一大批人犯。考试紧张情况下,人很容易下意识地把“错误的是”看成“正确的是”,我建议可以把题干里的关键词圈出来,宁可多花两三秒钟,也不要因为审题不清丢分。
8. 常见失分点与备考工具箱
8.1 最常见的五种丢分姿势
结合我见到的大量笔试案例,最常见的失分姿势有五种:一是不熟悉多选题的给分规则,在不确定时凭感觉多选,导致扣分;二是编程题没有在本地环境或草稿纸上先理清思路,直接上手写,写了一半发现逻辑有漏洞,耽误大量时间;三是简答题两三行就写完,没有分点论述;四是在CSS布局题上花费太多时间,导致后面的网络题没时间做;五是忽略了this指向和箭头函数这类基础细节,在简单题上失分。
如果有条件,我强烈建议提前用牛客网这类平台熟悉一下笔试环境。京东的笔试系统有自带的编辑器,没有智能提示,也没有报错高亮,如果你平时习惯了在IDE里写代码,第一次在网页编辑器里写会非常不适应,即使会做也可能因为漏了个分号被判错。
8.2 按题型备战的资料清单
客观题的部分,建议把MDN上JavaScript章节的核心概念通读一遍,重点看作用域、闭包、原型链、异步、事件循环这几个模块。配合刷题,我推荐“前端每日一题”类的小程序,每天刷两道选择题,一个月下来效果很明显。
编程题的部分,LeetCode的简单和中等难度题目是校招笔试的舒适区,重点刷数组、字符串、链表、二叉树这几类。不需要去啃hard题,校招笔试的算法难度基本是easy顶多到medium,京东的笔试编程题甚至更多偏向手写工具函数,所以打好JavaScript基本功比盲目刷题更重要。
8.3 这份老题的后续扩展方向
既然是2019年的题目,有些考点已经发生了明显变化。比如当时Vue还是2.x,现在Vue 3的组合式API已经成为主流;当时小程序还没那么普及,现在小程序已经成为大厂前端面试的常见话题。但笔试的底层逻辑没有变:考察基础是否扎实、是否具备独立解决问题的能力、是否愿意深挖原理。
如果你在这个基础上继续深入,建议把Vue 3和React 18的核心特性补上,特别是响应式原理的对比、hooks的闭包陷阱、并发渲染等。再把HTTP/2、HTTP/3的区别和前端性能指标(LCP、FID、CLS)补充到知识体系里,这些都是从2019年之后越来越高频的内容。
9. 关于备考,我最想分享的三句话
第一句话:基础决定下限。校招笔试不会考特别偏门的东西,翻来覆去就是JavaScript、CSS、浏览器、网络这几大块,把基础知识学扎实拿个及格分不难。真正拉开差距的是那些“好像知道一点但说不精确”的知识点,比如await后面表达式的执行时机、Cache-Control各个指令的组合效果。考前一个月,与其去追新框架,不如把旧知识里的模糊地带全部过一遍。
第二句话:手写代码能力需要日常积累。代码题不是靠考前突击就能写好的。我现在带新人的时候,会要求每周手写五个常用函数,从new、bind到Promise.all、深拷贝,都是笔试面试的高频题。手写代码能暴露出很多你以为会但实际上不会的地方,比如参数边界、空值处理、异常分支,这些在选择题里是看不出来的。笔试前把自己平时的手写代码整理成一个文档,看到哪一题不熟就重点刷哪一题,这是短时间内效率最高的备考方式。
第三句话:心态和时间管理在笔试中决定成败。京东笔试的题量不小,尤其是多选题和编程题并存的时候,很多人会陷入“前面多选题越做越纠结,后面编程题越来越慌”的恶性循环。我的建议是拿到卷子先快速浏览所有题目,客观题每道控制在1分钟以内,不会的先记录、跳过去,不要消耗情绪。编程题即使没写完整,也要把函数的框架和主要逻辑写出来,很多阅卷老师是看步骤给分的,空白卷肯定零分,半成品卷还有机会拿到一半左右的分数。