
2020年那阵子校招前端笔试乐信这套题算是在朋友圈流传比较广的一套。原因很简单它不像有些大厂笔试那样上来就是一堆偏题怪题而是把前端开发日常真正会碰到的知识点用选择题、简答题和手写题的形式串了一遍整体风格务实考察面覆盖了JavaScript基础、浏览器原理、框架应用、工程化和算法五个方向。我当时把整套题目完整做了一遍又对着参考答案逐题核对了细节今天把整套题的拆解和复盘整理出来希望能给准备校招前端岗、或者想自查基础是否扎实的朋友一些参考。这套题适合谁看如果你正在准备前端面试或者刚入行不久想系统梳理前端知识体系再或者你是带新人的前端组长想找一套质量不错的笔试题目来摸底都可以参考这篇复盘。我会按题型板块逐个拆解手写题会给出完整实现思路并解释每一步为什么这么写。1. 笔试整体结构与考察思路1.1 这套卷子到底在考什么乐信2020校招前端笔试题的题型大致可以分成四类单选题、多选题、简答题、编程题。从题目风格来看出题人明显不是想刁难人而是想筛选出“基础扎实、代码习惯好、有工程思维”的候选人。具体考察方向我梳理了一下基本围绕这几个模块JavaScript 核心机制原型链、this 指向、闭包、事件循环、异步编程这部分占比最高也是校招笔试题的绝对主力。浏览器与网络基础HTTP 缓存、跨域方案、浏览器渲染机制、前端安全这些决定了你能不能写出线上不会出问题的代码。框架应用能力Vue 响应式原理、虚拟 DOM、生命周期、组件通信乐信的技术栈以 Vue 为主所以框架题基本围绕 Vue 展开。工程化与性能优化模块化规范、构建工具、首屏优化、懒加载这部分考察你是否了解代码从编写到上线整个过程。算法与数据结构数组去重、排序、动态规划这类基础题难度不会超过 LeetCode 简单到中等但要求手写且考虑边界条件。有个很重要的信号是这套题里手写题占了很大比重而且不是让你写一个函数名就完事而是要求完整实现、考虑边界、必要时还要写注释。这说明公司希望招进来的人能直接上手写业务代码而不是只会背概念。1.2 题型分布与答题节奏建议整套题标准的笔试时间是 90 分钟到 120 分钟如果你在真实的笔试环境里节奏控制非常重要。我给当时自己定的策略是选择题和简答题控制在 30 到 40 分钟内完成剩下所有时间全部留给编程题因为手写题才是拉开差距的地方。选择题里有个特点不少题目是“二选一”的纠结题比如两个选项看起来都对但一个是充分条件一个是必要条件。这种题不要恋战先标记好做后面的回头再纠结。简答题则要注意书写结构分点作答比一团文字好得多面试官阅卷时一目了然。还有一个容易被忽略的点笔试系统如果支持本地 IDE 调试一定不要直接裸写。先把思路注释写清楚再逐步填充实现这样即使实现没写完至少思路分能拿到。我见过不少候选人函数名写对了但里边的逻辑一塌糊涂这种比“思路对但没写完”得分还要低。2. JavaScript 核心考点逐题拆解2.1 原型链与继承的两道题原型链是前端面试八股文里最经典也最绕的一块乐信这套题里出现了两道跟原型链直接相关的题目。一道是选择题给了三段代码让你判断输出结果另一道是简答题让写原型链继承的完整实现。选择题大概长这样function Parent() { this.name parent; } Parent.prototype.getName function() { return this.name; }; function Child() { this.name child; } Child.prototype new Parent(); var child new Child(); console.log(child.getName()); console.log(child instanceof Parent); console.log(child.constructor Parent);逐行分析child实例化时Child构造函数内部把this.name设置成了child所以child.getName()沿原型链找到Parent.prototype上的方法执行时this指向child返回child。child instanceof Parent为true是因为Child.prototype被赋值成了 Parent 的实例原型链上确实能找到Parent.prototype。第三个结果实际上是true原因在于Child.prototype被整体覆盖后child.constructor指向的是Parent这是个经典的坑。这道题暴露出来的问题在于很多人能答对第一问但第二问和第三问含糊不清。核心要理解instanceof检查的是原型的继承链而不是构造函数来源。如果你在答这类题时能把“原型查找路径”画出来或者用文字描述出来面试官对你好感度会直线上升。简答题让写一个“寄生组合式继承”这是目前最推荐的继承实现方式因为只调用一次 Parent 构造函数并且避免了在 Child.prototype 上生成多余属性。核心代码是用Object.create来创建父类原型的副本function inherit(Child, Parent) { Child.prototype Object.create(Parent.prototype); Child.prototype.constructor Child; }这里有个容易被忽略的细节一定要重新设置constructor否则实例的constructor会错误地指向Parent后续做类型判断时会踩坑。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()返回的是一个普通匿名函数这个函数在执行时没有任何调用者非严格模式下 this 指向全局对象。如果题目改成var fn obj.getName; fn();结果也会是window因为函数整体被抽出来调用后它内部指向就丢掉了调用者上下文。这套题里还考了一个高频闭包陷阱for (var i 0; i 5; i) { setTimeout(function() { console.log(i); }, 0); }输出结果是 5 个 5原因是var声明的变量 i 属于函数级作用域for 循环结束后 i 已经变成 5而所有回调函数共享同一个 i。如果改成let声明每次循环都会生成一个块级作用域输出 0 到 4。这道题还有一层变体如果要求必须用 var你怎么实现正确输出经典方案是用立即执行函数包裹for (var i 0; i 5; i) { (function(j) { setTimeout(function() { console.log(j); }, 0); })(i); }我在实际笔试里会在答案旁顺手写一句“因为函数参数是按值传递所以每次传入的 i 都被拷贝到了新的执行上下文里”这样面试官能看出你是真的理解而不是背答案。2.3 事件循环与异步输出顺序这道题算是整套笔试题里区分度最高的题目之一。给出的代码是这样的console.log(start); setTimeout(() { console.log(timeout); }, 0); Promise.resolve().then(() { console.log(promise); }); console.log(end);正确输出顺序是start、end、promise、timeout。核心逻辑是同步代码先执行完毕然后 JavaScript 引擎会先检查微任务队列把 Promise 的回调执行完之后才会执行宏任务队列里的 setTimeout 回调。这里的重点不是背结论而是要理解事件循环的完整流程。很多人在微任务里再嵌套微任务就会绕晕比如这道变体Promise.resolve().then(() { console.log(p1); }).then(() { console.log(p2); }); setTimeout(() { console.log(t1); }, 0)输出是p1、p2、t1因为 p1 执行后产生的 p2 依然属于微任务队列会在当前宏任务结束前全部清空不会把时机让给宏任务。这个机制是理解 async/await 行为的基础。我在实际做题时的经验是把代码分成“同步区”“微任务队列”“宏任务队列”三列按时间顺序往里填这样十拿九稳。这套题里还有个细节是async/await的题目本质上也是微任务的变体只要原理吃透怎么变形都不怕。2.4 手写防抖、节流与深拷贝手写防抖节流几乎成了前端笔试的保留项目乐信这套题里两个都考了还额外考了深拷贝这三道题放在一起考察的就是候选人写业务工具函数的基本功。防抖和节流的区别我用一句生活化的话总结防抖是“电梯等人”有人进电梯就重新计时等没人进才关门节流是“定时班车”不管后面多少人排队固定时间才发一趟车。代码实现上防抖的核心是setTimeout和clearTimeout的组合保证最后一次触发在延迟后执行function debounce(fn, delay) { let timer null; return function() { clearTimeout(timer); timer setTimeout(() { fn.apply(this, arguments); }, delay); }; }看到没有这个this和arguments的透传非常关键。如果不传在对象方法里 debounce 包装出来的函数内部 this 就会丢失实际业务中会出 bug。节流实现则有两种思路时间戳版和定时器版。时间戳版是立即执行定时器版是延迟执行。我会选择合并写保证既能保首帧又能保尾帧function throttle(fn, interval) { let last 0; return function() { const now Date.now(); if (now - last interval) { last now; fn.apply(this, arguments); } }; }深拷贝那题更有意思。题目明确要求“考虑循环引用”这直接卡掉了大部分人写的那种JSON.parse(JSON.stringify(obj))一行流。我给出的实现是这样function deepClone(target, map new WeakMap()) { if (typeof target ! object || target null) { return target; } if (map.has(target)) { return map.get(target); } const result Array.isArray(target) ? [] : {}; map.set(target, result); for (const key in target) { if (target.hasOwnProperty(key)) { result[key] deepClone(target[key], map); } } return result; }用WeakMap而不是Map的原因是当原对象不再被引用时WeakMap 里的键值对可以被垃圾回收防止内存泄漏。这是校招级别很少人能写出来的细节如果你在笔试里写出这个绝对是加分项。完整版本还需要处理 Date、RegExp、Map、Set但核心的循环引用环节只要过了这道题就拿下了。3. 浏览器与网络基础实操要点3.1 HTTP 缓存方案分析这套题里有一道简答题让你说出浏览器 HTTP 缓存的完整流程。这种题在实际开发中极其重要因为前端发布后经常遇到用户缓存不更新的问题本质就是没搞懂强缓存和协商缓存的关系。我的答题框架是分两层强缓存和协商缓存。强缓存阶段浏览器判断 Cache-Control 里的 max-age 或者 Expires如果没过期直接使用本地缓存不发任何请求如果过期了进入协商缓存阶段带着 If-Modified-Since 或 If-None-Match 去请求服务器服务器如果判断资源没变化返回 304浏览器继续用缓存如果变化了返回 200 和新的资源。这里有个核心坑点也是面试官真正想考的Cache-Control 的优先级高于 Expires而 ETag 的优先级高于 Last-Modified。为什么因为 Last-Modified 只能精确到秒同一秒内文件被修改两次就判断不出来而 ETag 是文件内容的指纹只要内容变了指纹一定变。我在业务里常用的一个组合是这样的Cache-Control: no-cache ETag: 特定的hash值no-cache的意思是“每次使用缓存前必须先向服务器验证”而不是“不缓存”。它配合 ETag 能兼顾性能和实时性比较适合活动页这类内容经常变动的场景。纯静态资源则用max-age31536000, immutable配合文件名 hash 来做永久缓存。3.2 跨域场景与解决方案跨域题目在乐信这套题里出现的形式是一道场景题页面前端调用一个第三方接口浏览器报跨域错误问怎么解决。这道题看起来简单但能真正答好的人不多因为它涉及前后端两侧的知识。最常用的方案有三个。CORS 是正统的方案后端在响应头加上Access-Control-Allow-Origin注意如果请求带有自定义 Header 或者使用非简单请求方法还需要处理 preflight 预检请求。JSONP 是利用 script 标签没有跨域限制的特性但只支持 GET而且需要后端配合返回特定格式的 JS 代码现在用的场景越来越少了。开发环境下最常用的是 webpack devServer 的 proxy 代理请求先发到本地开发服务器再由它转发到目标服务器绕开了浏览器的同源策略。我在笔试里答这道题会额外提一句上线后如果前端和后端域名不同通常会用 Nginx 做反向代理来转发/api路径的请求而不是在前端代码里写死跨域地址。这样好处是灵活后端地址怎么变都只改一层 Nginx 配置。这个细节能看出你有真实的上线经验而不是只会在本地调接口。3.3 渲染机制与性能优化浏览器渲染机制那题考察的是从输入 URL 到页面展示的完整过程虽然这是老生常谈但乐信这套题的加分点在于它要求“结合前端性能优化来分析”。这就不是死记硬背能答好的了。完整流程我通常这样描述先 DNS 解析域名得到 IP 地址然后建立 TCP 连接现在基本都是 HTTPS还要加上 TLS 握手发送 HTTP 请求拿到 HTML 文档浏览器解析 HTML 构建 DOM 树同时解析 CSS 构建 CSSOM 树两者合成渲染树经过布局、绘制、合成最终展示在屏幕上。要注意 JavaScript 在解析过程中默认会阻塞 DOM 构建所以 script 标签的defer和async属性就是在解决这个阻塞问题。能加到性能优化里的内容才是拉开分数的关键首屏白屏时间长的原因是渲染进程需要先等 HTML 解析完才能发下级的 CSS 和 JS 请求所以解决办法是内联关键 CSS或者用preload提前加载关键资源图片体积大是另一个常见的瓶颈所以要使用 WebP 格式、懒加载加上合适的响应式图片尺寸。答题时如果你能提到 LCP、FCP 这几个 Core Web Vitals 指标面试官会认为你真的做过性能监控。4. 框架题与工程化实战4.1 Vue 响应式原理与被考烂的 nextTick乐信这套题的框架部分明显是 Vue 技术栈为导向而且考得比较深。最典型的一道题是Vue 2 的响应式原理是如何实现的数据更新后 DOM 为什么不是立即更新Vue 2 的响应式核心是基于Object.defineProperty的 getter 和 setter 拦截。每个组件实例创建时Vue 会递归遍历 data 的所有属性把它们转换成 getter/setter 形式。当组件渲染时会读取这些属性触发 getter从而把当前渲染的 watcher 收集到依赖列表里当属性被修改时触发 setter通知所有依赖该属性的 watcher 重新执行也就是派发更新。这道题的隐藏考点是由于Object.defineProperty只能拦截属性的访问和赋值对于新增属性和删除属性是无能为力的所以 Vue 2 才提供了Vue.set和Vue.delete来解决这个问题。如果你能在答案里提到这一点并且说明Vue 3用 Proxy 从根本上解决了这个问题那这道题就答得相当完整了。nextTick 那题也很有代表性。Vue 在修改 data 后DOM 并不会立即更新而是把同一个事件循环里的所有数据变更合并起来在下一个微任务里统一更新组件。这样做的目的是减少不必要的 DOM 操作提升性能。nextTick 就是把回调延迟到下次 DOM 更新循环结束后执行的 API。实际开发中经常遇到修改数据后立刻用this.$refs拿 DOM 高度结果拿到旧值的情况解决办法就是在 nextTick 回调里读取。4.2 虚拟 DOM 与 Diff 过程这套题里关于虚拟 DOM 的题目是一个简答题为什么 Vue 需要虚拟 DOM虚拟 DOM 一定比真实 DOM 快吗第一问比较好答虚拟 DOM 的核心价值不是“快”而是“让跨平台成为可能”。因为虚拟 DOM 是一个普通 JS 对象它可以运行在浏览器、Node 端、小程序等各种环境里只要在对应平台实现 render 逻辑就能复用同一套组件逻辑。另一个价值是免去手动操作真实 DOM 的繁琐开发者只需要描述数据状态框架负责把状态映射成界面。第二问是个好陷阱。虚拟 DOM 不一定更快首次渲染时真实 DOM 操作反而更快因为虚拟 DOM 需要先创建虚拟节点树再做 diff。虚拟 DOM 的优势在于后续更新时它能用最小代价找到需要变更的节点减少不必要的 DOM 操作。另外在多平台渲染的场景下虚拟 DOM 的价值不是性能而是统一了编程模型。关于 Diff 算法重点要说明 Vue 是同层对比不会跨层级移动节点对比过程中用了头头、头尾、尾头、尾尾四个指针来快速判断处理列表时通过 key 来复用节点。这里有一个非常经典的考点为什么不建议用 index 作为 key因为当数组发生头部插入时index 全部错位Diff 认为所有节点都变了列表会被整体重新渲染性能反而更差。而且如果节点内部有状态比如 input 输入框整个状态还会错乱。如果你笔试时间充裕我会建议把这个场景写出来作为例子说明。4.3 模块化与构建优化工程化题目在这套题里占的比重不算大但有一道题值得拿出来复盘如何做前端项目的首屏加载优化答题时容易只想到压缩和懒加载但完整方案需要从整个加载链路上系统思考。首先在构建层面代码压缩、tree-shaking、按路由拆分代码块并配合动态 import 实现懒加载这些是最基本的手段。其次在应用层对于 SSR 或预渲染之外的普通 SPA要避免主包过大入口文件只引入核心依赖和路由配置不相关的组件全部按需加载。第三是静态资源层面图片用懒加载和现代格式把小的图片转成 base64 或者内联减少 HTTP 请求数。我当时还在答案里加了这样一个细节使用 dll 或 manualChunks 把第三方库单独拆包利用浏览器缓存特性让用户二次访问时只加载业务代码的增量而不是把所有代码重新下载一遍。这个思路在如今 Vite 时代依然有参考价值虽然配置方式变了但底层逻辑一致。模块化那题考的是 CommonJS 和 ES Module 的区别。需要答出几个关键点CommonJS 是动态的、运行时加载输出的是一个值的拷贝ES Module 是静态的、编译时加载输出的是值的引用。ES Module 之所以能做 tree-shaking正是因为它的静态性让构建工具在编译阶段就能分析出哪些导出没有被使用。5. 算法与手写题现场实录5.1 数组去重与排序不要只写一行数组去重是看起来最简单但实际能完整答好的题。我见过太多人一行Array.from(new Set(arr))交差应对笔试可以但面试官追问一句“如果数组里有对象怎么办”就卡住了。乐信这套题里数组去重也考了但题目要求“至少写出两种方案并说明各自适用场景”。这就是给候选人机会炫技的题我最后分了三个方案Set 适合基本类型、filter 加 indexOf 适合普通场景、对象键值或 Map 适合需要考虑类型和对象的场景。如果数组元素是对象用 Set 完全无效因为每个对象都是不同的引用真正的方案是用属性特征去重function uniqueObjects(arr, key) { const seen new Map(); return arr.filter(item { if (seen.has(item[key])) { return false; } seen.set(item[key], true); return true; }); }数组排序那题题目要求手写快排考察递归和分治思想。我在笔试里实现的标准版本是function quickSort(arr) { if (arr.length 1) return arr; const pivot arr[Math.floor(arr.length / 2)]; const left []; const right []; const middle []; for (let item of arr) { if (item pivot) left.push(item); else if (item pivot) right.push(item); else middle.push(item); } return [...quickSort(left), ...middle, ...quickSort(right)]; }注意本题里的细节把相等元素单独放到 middle 数组而不是丢到 left 或 right否则相等元素会导致递归死循环。我实际笔试时还额外补充了快排的平均复杂度和最坏复杂度并说明为什么最坏情况是 O(n²)这种“顺便把原理讲透”的做法对拿高分很有用。5.2 数组扁平化与最大子序和扁平化题目属于多解型选手考察的其实是 JavaScript 语言基本功。一道题让实现flatten([1, [2, [3, [4]]]])要求结果为[1, 2, 3, 4]我用了递归加 reduce 的实现function flatten(arr) { return arr.reduce((acc, cur) { return acc.concat(Array.isArray(cur) ? flatten(cur) : cur); }, []); }这一版足够通过但笔试时我还补了通配方案讲清楚Array.prototype.flat的默认展开一层传入 Infinity 可以无限展开以及 toString 和 split 组合的方式只适用于纯数字数组遇到字符串数组就会出错。这几个补充点展示了你对 JS 边界情况的敏感度。最大子序和是 LeetCode 经典题也是这套笔试题里唯一的动态规划题。题目是给定一个整数数组找出一个具有最大和的连续子数组返回其最大和。核心是定义状态dp[i]表示以第 i 个元素结尾的连续子数组的最大和状态转移方程是dp[i] max(nums[i], dp[i - 1] nums[i])最终答案是所有 dp[i] 中的最大值。笔试时我还顺便写了滚动数组优化把空间复杂度从 O(n) 压到 O(1)。这道题拿满分的关键不是写出来而是把状态转移方程写出来、用文字说明为什么这样设计再给实现。这正是校招笔试和社招面试里算法题的考察方式不只看你能不能 AC还看你能不能讲清楚。5.3 LRU 缓存实现LRU 是面试手写题里的常客乐信这套题也考了一道。题目设计一个 LRU 缓存类支持 get 和 put 操作容量有限当缓存满时淘汰最久未使用的数据。要求 get 和 put 的时间复杂度均为 O(1)。在 JavaScript 里最优雅的实现方式是基于 Map 的有序特性。Map 会记住键值对的插入顺序所以每次访问某个 key 时先删除再重新插入就能让它排到最末尾这样最久没用的数据自然就排在 Map 的最前面需要淘汰时直接删除第一个元素class LRUCache { constructor(capacity) { this.capacity capacity; this.cache new Map(); } get(key) { if (!this.cache.has(key)) return -1; const value this.cache.get(key); this.cache.delete(key); this.cache.set(key, value); return value; } put(key, value) { if (this.cache.has(key)) { this.cache.delete(key); } this.cache.set(key, value); if (this.cache.size this.capacity) { const oldestKey this.cache.keys().next().value; this.cache.delete(oldestKey); } } }这个实现已经足够通过笔试我自己在真实做题时还会补一句容量判断一定要放在 set 之后否则当 key 已存在且容量已满时你会在 set 新值之前误删另一个 key。这种边界问题是笔试题里最容易翻车的地方多花一分钟思考边角情况往往能挡住大多数竞争对手。6. 常见问题与避坑指南6.1 笔试现场最容易被扣分的点刷过大量笔试题之后我总结出校招笔试最典型的扣分点回头看乐信这套题也基本都踩过。第一个是只写答案不写过程。手写题要求实现某个功能你直接写一行最高级 API 的调用就算结果对面试官也看不到你的思路和编码习惯。校招批卷时手写题看的从来不只是最终结果而是步骤和表达能力。正确做法是先写思路注释再写步骤拆分再补实现。第二个是不注意题目细节。比如要求用 ES5 实现你通篇用了箭头函数和 const直接扣掉大半分。再比如要求在特定位置加注释你写了但注释内容没有解释清楚。我在实际笔试中碰到过要求“写出三种实现方案并说明适用场景”结果很多人只写了一种不是不会是没读完题。养成通读全题的习惯很关键。第三个是变量命名太随意。a、b、fn、temp这类命名虽然不影响运行但面试官看到的第一反应就是代码习惯不好。用debouncedFn、cacheMap、visitedSet这样的具名变量能给人留下“这个候选人会写生产级代码”的印象。这属于低成本高收益的加分项。6.2 针对校招与跳槽季的复习建议如果你正在准备前端笔试我给几条实际有用的建议而不是空泛的“多刷题”。首先按模块建一个自己的面试笔记。不要直接抄别人的面经而是把每一道题用自己的语言和代码再写一遍。比如这套题里的防抖节流和深拷贝你今天看完觉得懂了过两天不写一遍肯定手生。跟健身一样脑子记住了不代表手记住了。其次算法题要有策略地刷。前端笔试的算法题高频主要集中在数组、字符串、链表、栈、队列、简单的动态规划和哈希表。LeetCode 上的困难题在校招笔试里出现的概率不高性价比太低。优先刷简单和中等且每道题保证能写出暴力解和优化解两种方案。第三简历上列的项目一定要能被深挖。我这次做乐信这套笔试题时注意到框架和工程化题目虽然占比不小但真正的考察重心还是在基础是否能灵活运用。建议准备项目时把项目里用到的每一个技术点都往原理方向准备一层为什么用这个、底层怎么实现的、有什么替代方案、性能问题怎么排查。比如项目里用了懒加载你就要能说出路由懒加载的原理是什么import() 返回的是一个 Promise构建工具会把它单独打成一个 chunk 文件。关于复习节奏我的建议是提前两个月开始第一个月系统过基础第二个月专项刷手写和算法。每天保持两道代码题的量一套基础概念题的量周末拿一套完整卷子模拟笔试环境手机静音严格计时。这套练习方式坚持下去到真正笔试的时候心态会稳很多。6.3 笔试送分技巧先写注释再写代码最后分享一个我实测很管用的技巧笔试题里所有手写代码先在答题区域用注释把实现步骤列出来再在注释下面填代码。比如让你实现一个debounce你可以先写// 1. 定义 timer 变量保存定时器 // 2. 返回一个包装函数 // 3. 包装函数里清除上次定时器 // 4. 开启新定时器延迟执行回调 // 5. 透传 this 和 arguments function debounce(fn, delay) { let timer null; return function() { clearTimeout(timer); const context this; const args arguments; timer setTimeout(function() { fn.apply(context, args); }, delay); }; }这样做有两个好处一是避免写着写着思路断掉注释就是你的提纲二是万一时间不够没写完面试官也能从注释里看到你的完整思路这部分照样能给分。我在真实笔试中几次靠这个技巧在代码没完全跑通的情况下依然拿到了大部分分数。乐信这套2020年的校招前端笔试题放到现在来看考点依然没有过时甚至可以说非常接近真实业务对前端工程师的基本要求。前端面试准备没有太多捷径把基础模块一个个吃透再通过手写题把抽象概念转化成肌肉记忆踏踏实实积累后面不管是笔试还是面试都会顺畅很多。