news 2026/8/29 21:05:49

2015前端笔试题复盘:闭包、原型链与性能优化核心考点

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
2015前端笔试题复盘:闭包、原型链与性能优化核心考点

2. 这套卷子究竟在考核什么

最近整理旧笔记本里的资料,翻出来一份当年保存的人人网2015研发笔试卷E,前端方向。看着上面密密麻麻的批注,忽然觉得这套题放到现在复盘一下,依然挺有嚼头。虽然已经是好几年前的东西,但里面涉及的核心知识点——JavaScript 闭包、原型链、浏览器兼容、页面性能优化——恰好是每一代前端开发者都必须跨过去的坎。如果你正在准备面试,或者想检验一下自己的基础功底,这套卷子值得认真做一遍。

先说清楚这张卷子的背景。2015年的人人网正处于移动端浪潮的转型期,Web 端依然承担着大量用户交互场景,比如状态发布、相册上传、好友动态。笔试试卷分成通用技术基础和方向专项两块,既考验在校学生的知识面,也筛选扎实的前端基础能力。当时没有现在这么多框架轮子,笔试题大多围绕原生 JavaScript、浏览器机制、网络协议来出,反而更能看出一个人的内功深浅。

1. 试卷的整体结构与考察逻辑

1.1 2015年前端笔试为什么难

现在回想起来,2015年是一个很微妙的时间点。jQuery 还是绝大多数项目的标配,AngularJS 1.x 在企业里开始流行,React 刚刚进入国内技术圈的视野,ES6 虽然已经定稿但还没有大规模普及。这种技术交替期有一个特点:面试官知道新东西的出现是趋势,但团队里线上跑的还是老代码,所以笔试题目会同时覆盖“传统基本功”和“新方向敏感度”两条线。

传统基本功的考察集中在三块:JavaScript 的语言特性、浏览器兼容性处理、页面性能优化。而新方向敏感度,通常只会作为附加题出现,比如“是否了解 ES6 的新特性”“对组件化开发有什么理解”,占分不多但能拉开差距。人人网这套卷子也遵循了这个规律,整张卷面大约三分之二是基础题,三分之一是开放性设计题。

1.2 卷面模块分布与分值逻辑

从题型分布来看,常见的结构是这样的:

模块类型占比考察目标
HTML/CSS填空 + 简答20%布局基本功、语义化理解
JavaScript 基础写结果 + 代码补全40%语言特性掌握程度
浏览器/网络基础简答15%页面加载全链路理解
性能优化简答 + 方案设计15%实战经验
算法逻辑编程题10%基础算法能力

这里要特别提一下 JavaScript 部分为什么占这么大比重。2015年还没有 TypeScript,也没有现在这么完善的组件生态,前端交互全靠手写 JS 撑着。一个候选人如果连闭包、原型、this 指向都说不清楚,后续培养成本会非常高。所以笔试卷里 JS 的占比高,本质上是在筛选“能直接上手写交互的人”。

2. JavaScript 闭包与作用域:这张卷子的核心难点

2.1 经典闭包题目:循环里绑定事件

当年的笔试题里,出现频率最高的一道题长这样:

function bindClick() { var list = document.querySelectorAll('li'); for (var i = 0; i < list.length; i++) { list[i].onclick = function() { console.log(i); }; } }

问:点击第 3 个 li 时,控制台输出什么?答案是 3(如果列表长度足够),而不是 0、1、2。很多人当时第一眼会以为输出的是当前索引,但实际运行结果会让不少人懵一下。

原因在于var i声明在函数作用域内,循环结束后i已经变成了最终的列表长度值。所有点击回调函数引用的是同一个i变量,当事件真正触发时,循环早就跑完了,取到的自然是最终值。要修复这个问题,当时的常规方案是利用 IIFE 创建独立作用域:

for (var i = 0; i < list.length; i++) { (function(index) { list[index].onclick = function() { console.log(index); }; })(i); }

如果放在 2015 年,能写出这个 IIFE 版本已经算合格。如果还能补一句“用 ES6 的 let 声明也是可以的”,面试官会高看一眼。因为let在每个循环迭代中都会创建一个块级作用域绑定,这个问题从语言层面被直接解决了。

2.2 this 指向与作用域链的综合题

除了闭包,这张卷子还喜欢考察this的指向。有一个经典题目几乎每个版本都会出现:

var name = 'window'; var obj = { name: 'obj', getName: function() { return function() { return this.name; }; } }; console.log(obj.getName()());

答案是'window'。因为obj.getName()执行后返回了一个普通函数,这个函数在执行时并没有被 obj 对象调用,而是孤立的调用,所以this指向全局对象。在浏览器环境里,全局对象的name属性恰好就是'window'字符串。

这道题其实是在考一个关键概念:函数的this取决于调用方式,而不是定义位置。很多人把this和作用域链搞混,以为函数定义在 obj 内部,this就应该指向 obj,这是典型的误解。作用域链是词法层面的,而this是运行时绑定的,两者完全是两码事。

如果题目再加一个变体,问如何让返回值里的this指向 obj,解法就有三种:在外层函数里缓存var that = this,用bind绑定,或者用箭头函数。这三种写法在 2015 年的卷子上都能拿到分,但得分点不一样——能说出箭头函数的,说明对 ES6 有主动了解。

2.3 原型链:手写一个继承

当时还有一个高频考点是原型链继承。一个典型题目是:

function Animal(name) { this.name = name; } Animal.prototype.sayName = function() { console.log(this.name); };

要求写一个 Cat 类继承 Animal,并且 Cat 的实例能调用sayName方法。如果只知道默认的原型继承写法,这道题只能得一半分,因为很多人会写出这样的代码:

function Cat(name) { Animal.call(this, name); } Cat.prototype = new Animal();

这写法有个问题:new Animal()会生成一个带name属性(此时是 undefined)的实例,然后把它当作 Cat 的原型。如果 Animal 的构造函数内部有副作用或者需要参数初始化,这个调用会造成不必要的执行。更规范的做法是Cat.prototype = Object.create(Animal.prototype),然后修正Cat.prototype.constructor = Cat

为什么要把constructor指回来?这是一个细节考点。因为经过原型重写后,Cat.prototype变成了一个全新的对象,它的constructor默认指向Object而不是Cat,如果不手动修正,instanceof的结果不会受影响,但cat.constructor === Cat会变成 false,这在某些依赖constructor做类型判断的代码里会出问题。

3. 浏览器兼容与 DOM 操作:那年的基本功

3.1 事件处理的兼容差异

2015 年的笔试是不敢绕开浏览器兼容的,因为当时 IE6/7/8 虽然已经呈下降趋势,但 IE8 在部分企业环境里依然活跃。人人网的用户群体里,IE 用户占比远高于现在,所以前端面试题里必然会出现事件兼容的题目。

一个典型题目是:如何兼容 IE 和标准浏览器绑定事件?

function addEvent(elem, type, handler) { if (elem.addEventListener) { elem.addEventListener(type, handler, false); } else if (elem.attachEvent) { elem.attachEvent('on' + type, handler); } else { elem['on' + type] = handler; } }

关键考点有四个:一是attachEventon前缀不能漏;二是addEventListener的第三个参数false表示冒泡阶段触发,当时的主流实践是挂冒泡而不是捕获;三是attachEventthis指向window而不是当前元素,这差异很隐蔽;四是addEventListener可以给同一元素重复绑定多个相同事件,而onclick赋值会覆盖前一个。

顺带还要提一个比较高频的题目:如何阻止冒泡和取消默认行为。标准写法是e.stopPropagation()e.preventDefault(),IE 下则是e.cancelBubble = truee.returnValue = false。一道小简答题,能答全细节的人不多,因为大部分人只会记标准写法,对 IE 的写法不熟悉。

3.2 封装一个兼容的 XMLHttpRequest

除了事件,DOM 操作里还有一个常考的点是 Ajax 封装。当时已经开始用 jQuery 的$.ajax,但笔试想要的是让你不依赖库实现一个兼容的请求对象。

function getXHR() { if (window.XMLHttpRequest) { return new XMLHttpRequest(); } else { return new ActiveXObject('Microsoft.XMLHTTP'); } } function ajaxGet(url, callback) { var xhr = getXHR(); xhr.open('GET', url, true); xhr.onreadystatechange = function() { if (xhr.readyState === 4) { if (xhr.status === 200) { callback(xhr.responseText); } } }; xhr.send(null); }

这里还藏着一个考点:readyState === 4表示请求完成,但 HTTP 状态码是 200 才代表成功。有些人会把 304(走缓存)也当成成功处理,如果题目要求考虑缓存场景,通常还要判断xhr.status === 200 || xhr.status === 304。不过从实际产品角度,304 后浏览器往往已经帮你取到了缓存内容,responseText 里可能拿到的是空字符串,所以不能简单把它等同于请求成功。

3.3 获取元素位置的兼容处理

还有一道让我印象很深的题,要求写出获取元素在页面上绝对位置的函数。核心是offsetTopoffsetParent的循环累加,但要处理边界情况:

function getAbsoluteTop(element) { var top = 0; while (element) { top += element.offsetTop; element = element.offsetParent; } return top; }

考点在于:offsetParent可能为 null,所以循环条件要用element而不是element.offsetParentoffsetTop是相对offsetParent的位置,不是相对 document;还要注意position: fixed的元素offsetParent行为在不同浏览器下不一致。这题不算难,但能把边界条件考虑完整的人并不多。

4. 性能优化考点:笔试里的送分题与陷阱区

4.1 页面加载性能的经典考察

人人网这类内容型产品,页面首屏加载性能直接影响用户留存。笔试卷里有一道几乎必考的题:请列出你能想到的网页性能优化方案。

这道题看着是送分题,其实分水岭很大。基础差的同学会写出“压缩 JS/CSS”“合并图片”“用 CDN”这三板斧,但这只能拿基础分。高分答案通常还要覆盖以下几个方面:

  • 减少 HTTP 请求次数:合并脚本、CSS Sprites、内联小图
  • 资源加载策略:脚本放底部、样式放头部、按需加载非关键资源
  • 缓存策略:静态资源带版本号,利用浏览器缓存
  • 渲染层面:减少 DOM 操作、避免强制同步重排
  • 服务端优化:开启 gzip、设置合理的响应头

如果能在答案里写一句“对首屏非关键图片做懒加载”,面试官会觉得你有实际项目经验,因为这已经是 2015 年比较新的实践了。

4.2 重排与重绘:区分关键概念

有一道追问很常见:什么是重排(reflow)和重绘(repaint),哪些操作会引起重排?

这题考察的是对浏览器渲染机制的理解。把 JS 代码风格融入答案会更有竞争力:读offsetWidthscrollTopclientTop时,如果前面修改过样式但还没触发渲染,浏览器会强制同步重新计算布局,这是最容易引发性能问题的操作之一。解决思路是把读操作一次性收集起来,或者用requestAnimationFrame把写入延迟到下一次渲染帧。

当时的笔试卷上,能准确说出“读取布局属性会导致强制同步布局”的人非常少,因为大家只停留在“重排就是重新计算位置,重绘就是重新画”这种表面理解。如果有余力,可以在答题时补充一个例子:

var width = el.offsetWidth; // 读 el.style.width = width + 10 + 'px'; // 写

这种连续读写会造成多次布局抖动,高绩效答案会把读写分离。这部分虽然偏实战,但在笔试里简单提到就能加分。

4.3 懒加载的实现思路

卷子最后的信息题里,有一道问:如何实现图片懒加载?

这里不需要写出完整代码,但需要给出一套可落地的思路。常规做法是监听scroll事件,判断图片是否进入视口,一旦进入就把>function check() { var img = document.querySelector('img[data-src]'); if (!img) return; var rect = img.getBoundingClientRect(); if (rect.top < window.innerHeight && rect.bottom > 0) { img.src = img.getAttribute('data-src'); img.removeAttribute('data-src'); } } window.addEventListener('scroll', check);

这里有一个容易被忽视的点:getBoundingClientRect返回的是相对视口的位置,所以判断条件只需要比较rect.top是否小于视口高度即可,不用手动加scrollTop。很多人会搞混这个坐标系,写出来的判断条件复杂而且容易错。

5. 网络与缓存基础:一道简答题背后的知识体系

5.1 HTTP 状态码的掌握程度

网络基础在当年的笔试卷里不算大头,但一定会出现。常见的题目是:请列举 200、301、302、304、403、404、500、503 分别代表什么。

这道题的难点在于 301 和 302 的区别,以及 304 的缓存机制。301 是永久重定向,浏览器会缓存重定向结果,后续请求直接跳到新地址;302 是临时重定向,每次请求还是先访问原地址。真实项目中,301 常用于域名迁移,302 常用于未登录跳转。能答出这个场景区别,说明不只是背状态码,而是理解过实际业务。

304 这个状态码也很容易答偏。304 表示的是“服务端资源未修改,可以用缓存副本”,不是一种错误。整个交互过程是:客户端请求资源时带上If-Modified-SinceIf-None-Match,服务端检查后发现资源没有变更,就返回 304 和空响应体,客户端接着用本地缓存。这可以减少不必要的传输。很多人把 304 和“请求失败”画等号,这在缓存面试题里是明显扣分点。

5.2 浏览器缓存的几个响应头

关于浏览器缓存,还有一道简答题:说说ExpiresCache-ControlETag的区别。

Expires是 HTTP/1.0 时代的产物,指定一个绝对的过期时间,但客户端时间和服务器时间不一致时会出问题。Cache-Control是 HTTP/1.1 的标准,max-age指定相对存活时间,更可靠。ETag是实体标签,比较内容是否变化,配合If-None-Match使用。强缓存和协商缓存的先后顺序应该是:先看Cache-Control/Expires,没命中再看ETag/Last-Modified

为了讲清楚,我发现一个生活类比很好用:强缓存就像是冰箱里的酸奶,上面写着保质期,保质期内你直接喝就行,不用问商家;协商缓存像是你拿着旧照片去问商家“这个商品是不是还是这样”,商家说没变你再继续用。

这道题能拿高分的同学,通常还会主动提一嘴:Last-Modified的精度是秒级,如果资源在 1 秒内被修改两次,就检测不到变化,所以ETag更可靠。这种小细节,不是背题能背出来的。

6. 算法逻辑与开放设计题:从笔试卷看思维格局

6.1 字符串处理类的简单算法题

2015年的前端笔试题对算法要求不算高,通常是一两道数组/字符串处理的基础题。最常见的题目是:写一个函数判断字符串是否为回文。

function isPalindrome(str) { str = str.replace(/[^0-9a-zA-Z]/g, '').toLowerCase(); return str === str.split('').reverse().join(''); }

考察点是字符串的常用方法组合:正则去除非字母数字、转为小写、分割反转再拼接。还有一种写法是用双指针从两端向中间比较,复杂度是 O(n),但笔试实际考察的主要是基本功是否熟练,而不是复杂度优化。

还有一道字符串去重的题目也出现过:

function unique(str) { var result = ''; for (var i = 0; i < str.length; i++) { if (result.indexOf(str[i]) === -1) { result += str[i]; } } return result; }

如果能写出indexOf已经可以,如果写一个Object作为哈希表去重,那就更靠近高级答案。这说明你对 JavaScript 数据结构有实际应用能力,而不仅是会用 API。

6.2 组件设计题:怎么设计一个轮播图

开放设计题在整个卷子里最有区分度。常见的一道题:请设计一个图片轮播组件的 API 和核心逻辑,要求支持自动播放、循环播放、点击切换。

这道题不要求写完整代码,但要求描述清楚结构。我当时给出的思路是:对外暴露initgoToprevnextplaystop方法,内部用索引currentIndex维护当前状态,用setInterval实现自动播放,切换时计算偏移量并设置容器的transformleft值。

更高质量的答案会补充两个设计细节:一是循环播放时的无缝衔接怎么做(第一张前面克隆最后一张,或者到边界时直接跳转但带过渡动画);二是自动播放时鼠标 hover 要暂停,离开后恢复;三是如果用户快速点击多次,要防止动画堆积,最好做节流或重置定时器。能主动想到这些边界情况的人,在项目里大概率是一个靠谱的开发者。

7. 复盘:这份卷子给今天的前端开发者留下了什么

7.1 2015年与现在的考点变化

现在回头看这份卷子,有些知识点已经成了历史,比如attachEvent,没有人在新项目里会用到;但更多内容只是换了一副面孔出现。闭包依然是面试高频题,只是提问方式变成了“这段 React 代码为什么拿不到最新 state”或“这个闭包内存泄漏怎么排查”。性能优化还是必考,只是从“合并静态资源”升级成了“分析 LCP、FCP、CLS”。

我最大的感受是:通识知识的折旧速度比想象中慢。当年花了很久搞懂的this指向问题,在 React 类组件里依然让人踩坑;当年在笔试题里画的原型链,在封装高阶组件时照样用得上。反过来说,那些只背 API 而不理解原理的候选人,到了今天这个框架生态里依然很难适应。

7.2 准备笔试的三个建议

结合当年备考和带新人的经验,我给准备研发笔试的同学三个建议。

第一,把 JS 的语言机制吃透,不要只刷 API。闭包、作用域链、原型链、事件的运行机制,这些是前端面试的“母题”,任何框架题背后都逃不开这些。第二,做笔试题时不要把思路写得太跳跃,面试官看的是你的推导过程,代码写不出来,哪怕用文字把解决思路写清楚也有分。第三,考前了解一下目标公司的主流技术栈,在开放题里体现出你对该技术方向的了解,而不是空谈概念。

8. 关于这套笔试卷的一点点后记

我记得当时做完这套卷子之后,还特意去找了几家同学对答案。有人觉得这些题目太“基础”,和实际项目脱节,但后来工作几年再回头看,这些基础其实是所有业务的底层地基。直到现在,我面试候选人时依然会不自觉地用闭包、this、事件代理这几个问题来试探对方的 JS 功底,无论对方简历上写了多少个框架。

如果你正打算投递前端岗位的研发校招,不妨把这套卷子的知识点过一遍。不用背答案,而是要把每个问题背后的原理搞清楚,尤其是“为什么”这个层面理解了,面试官问什么变体你都不慌。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/29 20:53:55

SpringBoot实战:毕业生招聘平台全栈开发与毕业设计指南

简介&#xff1a;SpringBoot作为Java领域主流的Web开发框架&#xff0c;以其‘约定大于配置’的理念和快速启动能力&#xff0c;极大地简化了企业级应用的开发与部署流程。其核心原理在于通过自动配置和Starter依赖&#xff0c;整合了Spring生态的诸多组件&#xff0c;使开发者…

作者头像 李华
网站建设 2026/8/29 20:51:52

魔镜占卜 H5 小游戏:AI 占卜 + 周易,支持多平台运行

项目简介 「魔镜占卜」是一款基于 H5 技术开发的占卜类小游戏&#xff0c;融合了传统周易文化与现代 AI 技术。项目支持在微信、百度、头条等多个平台运行&#xff0c;并集成了 双 AI 引擎&#xff0c;为用户提供智能化的占卜体验。 项目采用 Java 作为后端开发语言&#xff0…

作者头像 李华
网站建设 2026/8/29 20:45:30

Matlab地图可视化实战:用scatter与plot实现数据空间分布与关联分析

1. 项目概述&#xff1a;从数据到洞察&#xff0c;地图可视化的核心价值 在地理信息分析、区域经济研究、物流路径规划乃至社会科学调查中&#xff0c;我们常常会面对一组带有地理位置坐标的数据点。这些数据可能是全国各城市的GDP、一条河流沿途的水质监测值、多个物流仓库之间…

作者头像 李华
网站建设 2026/8/29 20:41:48

Ganzlab‑Glink 深度解析:国产化 MBD 图形化建模环境入门与实战

在汽车电控 MBD 开发流程中&#xff0c;图形化建模、混合系统仿真、自动代码生成、SIL 软件在环是控制算法开发的核心链路。Glink 作为 Ganzlab 平台下专门面向基于模型设计的图形化建模环境&#xff0c;面向动力域、底盘域、车身域电控开发&#xff0c;完成从算法建模、离线仿…

作者头像 李华
网站建设 2026/8/29 20:40:33

配电变压器检测数据集构建与YOLO模型训练全流程实战

简介&#xff1a;目标检测是计算机视觉的核心任务之一&#xff0c;旨在识别图像中特定物体的位置和类别。其原理通常基于深度卷积神经网络&#xff0c;通过提取图像特征并生成候选框来实现精准定位。这项技术在工业自动化、智能安防等领域具有极高的技术价值&#xff0c;能显著…

作者头像 李华