2016校招前端笔试题复盘:JavaScript基础与浏览器原理是核心
发布时间:2026/8/29 23:18:18 作者:尧图编辑部 阅读量:1,286

2016年那会儿前端圈子其实处于一个很有意思的过渡期。jQuery还是很多项目的默认配置Bootstrap做后台页面司空见惯AngularJS和React已经开始有人讨论但大多数校招笔试的考法跟今天差别并没有想象中那么大。用友那年校招的web前端笔试题我印象最深的是它“不过分追新”的风格考的全是JS语言本身、浏览器原理、网络基础这些硬功夫反而比后来那些追框架、追工具链的题目更值得复盘。这篇文章我想借这套题把前端笔试背后的考察逻辑拆开讲透。无论你是正准备校招的应届生还是已经工作几年想回头补基础的前端开发都能从中找到一些“当时没想明白”的答案。笔试题这东西真正的价值从来不是背答案而是通过它理解面试官到底在筛选什么样的人。1. 题目整体设计与意图拆解1.1 当年校招笔试的题型分布根据当时参加过笔试的同学反馈和我对这类经典题型的了解用友2016校招前端笔试题型大致可以分成四类单选题、多选题、程序结果分析题、手写代码题。没有后来常见的问答题和开放设计题整体更偏向“基础知识的广度 代码能力的底线”。题型考察方向典型内容建议用时单选JS基础、HTML/CSS、网络数据类型、事件、HTTP状态码15分钟多选容易混淆的知识点闭包、作用域、与、数组方法15分钟程序结果分析代码阅读与运行逻辑变量提升、this指向、异步执行顺序25分钟手写代码基本功与算法思维数组去重、字符串处理、简单排序35分钟这个结构放在今天看依然合理。笔试时间一般控制在90分钟题量在30道左右。它的目的不是让你“全做完”而是通过有限的时间判断你对基础知识掌握的熟练度。很多人死在“前面选择耗时太多后面大题没时间写”这本身就是一种筛选——看你有没有大局观。1.2 设计意图校招笔试到底想筛什么校招和社招最大的区别在于应届生基本没有真实项目经验面试官能考察的只有基础理论、逻辑思维和学习潜力。所以笔试的设计逻辑其实很朴素——基础题摸广度编程题摸深度分析题摸思维习惯。用友这类To B软件公司前端岗位要做的是企业级管理系统、大屏展示、流程引擎这类偏复杂的后台应用。这些项目对基础稳定性要求极高一个闭包用错就能导致整个报表页面崩溃。所以它们笔试题几乎不考框架因为jQuery和Backbone这类框架可以入职后一个月学会但原型链、事件循环、作用域这种东西学不会就永远写不出可靠的代码。提示如果你现在准备校招看到笔试题里全是基础题不要觉得“太简单”或者“太老”。基础题不是送分题而是高压线上的探针每个选项都在试探你理解得够不够深。2. 核心考点解析与答题思路2.1 JavaScript语言基础四个必考重灾区我当时帮人复盘这份笔试题时发现JS基础部分的考点高度集中几乎可以用“四个必考”来总结数据类型与类型转换、闭包与作用域、this指向、原型链与继承。这四个点占到基础部分的70%以上。数据类型这关最大的坑是“看似简单实则混淆”。typeof null返回object、[] false返回true、1 2得到字符串12这些都是经典陷阱。更隐蔽的是数组方法在隐式转换时的行为——[1,2] [3,4]得到1,23,4因为数组先调toString()变成字符串再拼接。这类题看起来是“脑筋急转弯”实际上考察的是你对隐式转换规则的掌握是死记硬背还是真正理解。闭包与作用域的题常见形式就是“下面代码输出什么”。比如for (var i 0; i 5; i) { setTimeout(function() { console.log(i); }, 100); }这道题考的是var没有块级作用域、setTimeout回调在循环结束后才执行、闭包捕获的是变量引用而不是值。答案不是0,1,2,3,4而是5,5,5,5,5。当年很多人栽在这里。改成let之后输出0,1,2,3,4的差异以及用立即执行函数闭包保存i的模式都属于标准解法。这个知识点直到现在依然是面试高频题因为异步加闭包是前端代码出bug的重灾区。this指向的题本质上考的是“调用方式决定this”这条铁律。普通函数调用、对象方法调用、构造函数调用、call/apply/bind调用四种场景下this各不相同。当年经典题是这样var name window; var obj { name: obj, getName: function() { return function() { return this.name; }; } }; console.log(obj.getName()()); // window因为obj.getName()执行后返回了一个普通函数调用时没有调用者上下文所以this指向window。要拿到obj就得在闭包里保存this也就是var self this。这个问题在回调函数、事件监听、定时器里非常常见值得反复练习。原型链考的是“构造函数、实例、原型对象三者的关系”。instanceof判断的是原型链上是否存在对应原型而hasOwnProperty只判断自身属性。继承的典型手写题是Object.create的实现或者用寄生组合式继承写一个Animal和Dog的继承关系。这类题不要求你写出完美代码但要体现出你对“属性查找沿原型链逐级向上”这一机制的认识。2.2 浏览器与网络基础为什么前端必考这个前端笔试考浏览器和网络在2016年并不算“超纲”。用友的题里出现过的几个方向包括事件冒泡与捕获、页面加载流程DOMContentLoaded和load的区别、HTTP状态码语义、跨域问题的常规解决方案。事件模型属于“必须理解到位”的内容。事件冒泡是从目标元素向上传播到document事件捕获是从document向下传播到目标元素。addEventListener的第三个参数传true表示捕获阶段触发不传或传false表示冒泡阶段触发。考得深一点的会问“事件委托的原理”——利用冒泡将子元素的事件统一交给父元素处理优点是可以处理动态添加的节点以及减少事件绑定数量。这个知识点在今天的React/Vue项目中依然有用事件委托本质上没有过时。HTTP状态码也是选择题常客。304表示“使用缓存资源”403是“禁止访问”404是“资源不存在”500是“服务器内部错误”。笔试一般考到这种程度就够了。但如果你能在答题时额外说明“301和302的区别是永久重定向和临时重定向这会影响浏览器对缓存的处理”会显得你确实懂网络而不是背过状态码。跨域问题是2016年面试的“必答大项”笔试里一般不会让你写完整方案更常见的是以简答形式问“列举解决跨域的方式并说明原理”。常规答案包括JSONP动态script标签不受同源策略限制利用回调函数接收数据、CORS服务端设置Access-Control-Allow-Origin响应头、代理转发同源服务器做中间层转发请求。当时Nginx代理用得很多devServer.proxy这种原理倒是后来才普及的。这类题不用写太多但要思路清晰、顺序合理。2.3 手写代码题算法不难难在工程习惯手写代码题一般在两道左右一道数组相关一道或者两道是字符串和逻辑类。典型题目有数组去重、数组扁平化、实现防抖节流、字符串反转、找出字符串中出现次数最多的字符、手写类型判断函数。这类题考察算法程度其实很浅难度大概在LeetCode easy级别。但面试官真正想看的不是算法效率而是——变量命名规不规范、有没有考虑边界情况空数组、空字符串、null传入时会不会报错、代码逻辑是否容易读懂。这些才是企业级开发中最重要的能力。注意笔试手写代码不要为了追求“一行代码搞定”而牺牲可读性。Array.from(new Set(arr))确实能数组去重但如果你能同时写出reduce循环版本并解释差异面试官会更认可。多解法体现了维度不同的思考。3. 这套笔试背后的能力模型图谱3.1 从笔试题看2016年的前端技术生态2016年对前端行业来说是一个很特殊的年份。当年jQuery依然是绝大多数公司项目的基石$.ajax和$(document).ready几乎是每个前端日常都会写的代码。AngularJS 1.x在企业级应用里有一席之地React刚刚起步Vue 2.0在这一年发布Webpack正在取代Grunt和Gulp成为主流打包工具。用友的笔试题没有直接考这些框架但它考的所有基础知识点都是这些框架底层运行的基石。jQuery的$(selector).on(click, fn)本质上就是事件委托的封装。Vue 2.0的响应式原理离不开Object.defineProperty而这个API本身就在考察你对“对象属性描述符”的理解。React的合成事件系统也要依赖冒泡机制。这说明一份有质量的笔试题考的不是“技术潮流”而是“技术底部”。现在回头看我当时觉得“这套题真老”的想法是错的。后来我面试候选人时发现很多简历上写着React/Vue项目经验的人问他冒泡和捕获都说不清楚问他setTimeout和Promise的执行顺序也支支吾吾。框架可以快速学基础是慢功夫。招聘方用笔试筛基础就是这个原因。3.2 分层筛选逻辑基础合格思维加分一份好的笔试题除了判断“会不会”还能判断“好不好”。同样是数组去重思路不同反映的水平完全不同。提交代码问题能力判断for循环 indexOf能跑但复杂度O(n^2)且indexOf对NaN无效至少会写代码filterindexOf代码简洁但依然O(n^2)ES5时代的常规操作见过一些写法new Set()代码最短但不懂Set的兼容性了解ES6但不深reduce Map复杂度O(n)思路完整兼容性好有算法意识同时写出去重后再排序并说明稳定性考虑全面表达清晰工程思维较强面试官不只看能不能通过还看你的解题路径。如果只写new Set(arr)说明你只是“听说过ES6”。如果写reduce 对象存储并说明typeof区分1和1的问题说明你真的处理过数据。这套分层逻辑在校招笔试里体现得尤其明显——大家都没有项目经验区分度主要靠“基础扎实程度”和“思维细腻程度”。这也解释了为什么同一道题不同人得分可能天差地别。4. 经典题的实战模拟与参考实现4.1 基础概念题速测你能答对几道这里还原一份我整理的经典基础题速测不严格对应某一年的原题但覆盖方向一致。你可以先自己做一遍再对照后面的解析。typeof undefined typeof null这句判断的结果是什么5 - 1和5 1分别输出什么console.log(1 2 3)输出什么var a {n: 1}; var b a; a.x a {n: 2}; console.log(a.x) 和 console.log(b.x)的结果如何判断一个变量是否为数组null undefined和null undefined的结果是什么setTimeout的this在非严格模式下指向什么[1, 2, 3].map(parseInt)的结果是什么逐题说一下。第1题typeof undefined是undefinedtypeof null是object字符串比较结果是false。这道题错的人很多因为null undefined是true但typeof的结果是字符串比较的是字符串字面量。第2题5 - 1得到数字4减法触发隐式转换将字符串转数字5 1得到字符串51因为加号有一端是字符串时执行拼接。第3题从左到右计算先1 2得3再3 3得33。第4题是一道经典的连续赋值题。a.x a {n: 2}中a.x引用先确定指向原对象的x属性然后a被重新赋值最后将新对象赋给原对象的x属性。结果是a.x为undefined而b.x指向新对象。这题考察引用赋值和赋值顺序少见但能有效拉开区分度。第5题判断数组用Array.isArray(arr)在ES5之前也有Object.prototype.toString.call(arr) [object Array]的通用方法。arr instanceof Array在多iframe环境下不可靠因为不同全局对象各有各的Array构造函数。我记得当时有同学写typeof arr object这只能判断它是引用类型不能判断它是数组。第6题null undefined为true宽松相等认为它们相等null undefined为false类型不同null是objectundefined是undefined。第7题setTimeout中的回调函数非严格模式下this指向window或全局对象严格模式下是undefined。第8题parseInt作为map的回调函数会被传入三个参数当前值、索引、数组本身实际上是parseInt(1, 0)、parseInt(2, 1)、parseInt(3, 2)结果是[1, NaN, NaN]。这题在2016年属于“见过才不亏”的冷门考点但到今天已经变成常规面试题。4.2 手写编程题的完整思考过程以一道经典编程题为例实现一个函数将数组扁平化并去重最后升序排列。例如输入[1, [2, 3], [4, [5, 6]], 1, 2]输出[1, 2, 3, 4, 5, 6]。我的建议答题顺序是先写一个能跑的版本再优化。第一步数组扁平化。递归是最直观的思路function flatten(arr) { var result []; for (var i 0; i arr.length; i) { if (Array.isArray(arr[i])) { result result.concat(flatten(arr[i])); } else { result.push(arr[i]); } } return result; }这个版本的优点是兼容性好ES5环境下也能运行。缺点是递归处理如果嵌套层级极深可能有栈溢出风险。它对应“面试官问你这个方案的问题在哪里”时你要能说出来。第二步去重。如果允许ES6Array.from(new Set(flattened))最短。如果考虑兼容性可以用reduce加对象存储function unique(arr) { var map {}; return arr.filter(function(item) { if (map[item]) { return false; } map[item] true; return true; }); }注意这里map[item]用对象的key做去重会把数字1和字符串1混在一起实践中有隐患。更严谨的写法是map[typeof item item]。这一步能体现你比别人多想的细节。第三步排序。用Array.prototype.sort默认按字符串排序数字升序必须传比较函数function(a, b) { return a - b; }。完整版function flattenUniqueSort(arr) { var flat flatten(arr); var uniq unique(flat); return uniq.sort(function(a, b) { return a - b; }); }这道题三合一综合考察递归思维、类型判断、数组方法和边界处理。踩坑点集中在忘记数组扁平化后还是引用类型、去重时对象key的类型合并、排序时默认字典序问题。如果你能把每一步为什么这么写的理由说清楚面试官会觉得你不仅是“背了题”而是理解了。4.3 开放题怎么答才有亮点2016年用友的笔试题虽然没有开放设计题但当时的面试环节会有类似“如果要你优化一个页面的加载速度你的思路是什么”这样的追问。笔试里如果附带简答题也常见“说明AJAX请求的完整过程”“你怎么理解前端模块化”这类开放性题目。开放题的答题策略不是追求“唯一标准答案”而是展示分析框架。以“优化页面加载速度”为例一个好的回答应该按层级展开资源层面压缩JS/CSS文件、合并请求、使用CDN、开启gzip渲染层面CSS放头部、JS放底部或加defer/async、减少DOM层级缓存层面合理设置Cache-Control和ETag利用浏览器缓存数据层面接口按需加载、首屏只请求关键数据、图片懒加载。只回答“压缩JS/CSS”是不够的因为这属于最基础的背答案。如果你能进一步说明“CSS阻塞渲染、JS阻塞解析所以CSS要尽快到达浏览器JS可以延迟执行”就体现出你真的理解浏览器工作方式。这个层次感在开放题里非常加分。5. 常见问题与避坑经验5.1 这道题为什么会做错典型错误盘点我帮人改笔试题的时候积累了一大堆“一眼就能看出问题”的错误。最普遍的是分号问题和变量命名问题手写代码时经常有同学不写分号、变量名全是a、b、c。这不是致命错误但在团队协作里会显得不职业。笔试阅卷人对“看起来像不像能直接部署的代码”非常敏感。逻辑层面的错误更多集中在类型比较上。和乱用是重灾区。写数组去重用result.indexOf(item) -1判断存在性结果遇到NaN就失灵。写字符串处理不考虑大小写和空格导致函数一遇到真实数据就崩。这些不算“不会做题”而是“缺少工程意识”而工程意识恰恰是企业最看重的。时间分配错误也很可惜。基础题卡壳太久导致后面高分的编程题只能草草收尾。我见过不少同学小题错2道、大题全空的卷子。正确的策略是基础题每题最多2分钟超过就先跳过代码题至少留30分钟。5.2 复盘这套题哪些经验到现在还能用距离2016年已经过去很多年我看着这份笔试题最大的感受是基础知识的考察方式在变但考察对象没变。当年考闭包输出现在依然考闭包输出当年考数组去重现在最多加一个“写出三种实现并说明复杂度”当年考事件循环现在考Promise、async/await的执行顺序。核心永远是“你对这门语言理解得有多深”。对于准备校招的读者我的建议是不要只刷题库。把ES5中数组相关方法map、filter、reduce、forEach、sort的底层行为和常见坑过一遍把闭包、this、原型链、事件循环这四座大山翻来覆去理解透比刷100道“押题”管用得多。笔试的题目可以换但内核不会变。提示面试前找一套两三年前的笔试题练手不是让你背答案而是让你感受出题人的视角。你在做2020年以后的题目时可能已经被框架淹没而看老题会让你重新意识到JS这门语言本身才是最值得花时间的。结尾关于基础我的真实体会工作多年之后回头看2016年这份“老掉牙”的笔试题我反而觉得它出得相当扎实。后来我面试过很多候选人真正让我留下深刻印象的不是谁简历上写了多少个框架而是谁能在白板上把this指向讲清楚、能把闭包的实际用途说出个一二三。技术栈每两三年就换一轮但基本功是十年不变的东西。如果你还在准备校招建议认真做一遍类似的老题并且别只看答案多问问自己“为什么”如果你已经工作偶尔翻翻这类基础题也能帮你从日常的业务逻辑里跳出来重新审视那些很久没再细想的JS原理。这是我个人觉得最值得保留的学习习惯。