用友校招前端笔试题解析:JavaScript基础与浏览器机制核心考点
1. 一纸笔试题背后的筛选逻辑用友想要什么样的前端先把时间轴拉回2017年。那会儿的前端圈子和现在完全不是一个玩法ES6还没彻底普及TypeScript只是少数人的玩具Vue 2.5刚把生态补齐React 16还没发布Angular还在使劲往企业级市场里挤。用友作为国内老牌企业管理软件厂商校招笔试自然带着一股典型的“B端业务”气质——不考花架子不问你知道不知道最新框架的某个API而是踏踏实实检查你的JavaScript语言基本功、对浏览器运行机制的理解、以及能不能写出健壮可维护的代码。这套题拿出来和当年阿里、腾讯的校招笔试题对比能明显感受到风格差异互联网大厂爱考算法、考工程化、考场景设计用友这种ERP厂商则更在意你能不能在一个五六百人共用的报表系统里写出不出错的脚本。如果你准备过用友的校招你得先理解一个核心事实用友的软件卖的是稳定性和业务逻辑不是前端炫技。他们的产品里前端面对的是审批流、单据列表、财务凭证、人力资源管理界面用户是企业里的财务人员、HR、仓库管理员。这些用户不会在乎你用了什么潮流框架他们只要求“点这个按钮它必须触发正确的动作”“表格数据在IE下不能乱掉”“千万别因为一段JavaScript报错导致整单保存不了”。所以笔试里大量题目是在考察这种硬约束下的基本功变量作用域、闭包陷阱、事件冒泡、DOM操作、数组去重、字符串处理、经典排序。你把这些吃透了不一定能进互联网大厂但一定能过用友的笔试关。另外要提醒一句2017年的笔试和现在有个很大不同当时相当多题目是直接把代码写出来让考生手动模拟执行结果。也就是给一段带陷阱的JavaScript问你console.log打印什么。这种题不依赖任何环境纯粹看语言理解所以它比你现在刷LeetCode更能暴露一个候选人的基础薄弱点。用友喜欢考这类题是因为他们面试官自己就是靠调试这类bug长大的考察方式自然带着当年的编程习惯。准备这类老牌企业的校招题我的建议是别去刷“最新知识点面经”而是把《JavaScript高级程序设计第三版》这个级别的书从头到尾过一遍再把历年笔试题按类型拆开逐题搞懂搞透。下面我按当年这套笔试题的常见模块把题目类型、背后考点和答题套路一条条拆给你看。2. 语言基础题作用域、闭包和变量提升的“送命题”2.1 一段写满陷阱的代码是筛选器也是照妖镜几乎所有前端校招笔试题里都会出现一整块“看代码写输出”的题目用友的题目尤其爱这么干。比如下面这类经典陷阱当年就出现过变体var a 100; function test() { console.log(a); var a 200; console.log(a); } test();很多基础不牢的同学一看到第一行console.log(a)就顺手写100理由是全局变量a不是定义了吗错了。因为函数内的var a声明的变量会被提升到函数作用域顶部相当于function test() { var a; console.log(a); // undefined a 200; console.log(a); // 200 }这个题本质考察的是变量提升hoisting和词法作用域两个概念的叠加。ES5时代var声明的变量会将“声明”提升到当前作用域顶部但不会把“赋值”也提上去而声明一旦提升外层的同名变量在函数内部就被“遮蔽”掉了于是第一个console.log(a)输出的是undefined而不是100。第二个输出200没有什么悬念。这类题在当年属于“白送分”题型但也属于一眼就能筛掉半吊子候选人的题型。如果你在笔试现场遇到这类题我的经验是先自己写一遍执行顺序再在卷子上把变量提升后的代码结构画出来最后再写结论。这个过程既帮你理清思路也能让面试官在阅卷时看到你的分析能力后面人力筛简历时这个印象分是真实存在的。2.2 闭包不只考原理还考“能不能说出应用场景”闭包是校招笔试的必考题目用友的题一般会分两层来考。第一层是基本语义理解比如问什么是闭包它有哪些特性第二层就直接甩一段代码for (var i 0; i 5; i) { setTimeout(function() { console.log(i); }, 100); }请问输出什么这道题考的是“闭包捕获变量引用”和“事件循环延迟执行”的组合。正确答案是连续输出五个5。因为var声明的i是函数级作用域五个setTimeout回调共享同一个i变量等到100毫秒之后回调执行时循环早跑完了i已经是5所以每个回调都读到5。当年的主流修复方案是用IIFEfor (var i 0; i 5; i) { (function(j) { setTimeout(function() { console.log(j); }, 100); })(i); }或者用ES6的let声明把每次循环的i绑定到当前迭代块级作用域里for (let i 0; i 5; i) { setTimeout(function() { console.log(i); }, 100); }这道题的价值不在于“会不会修复”而在于你能不能把原理讲透为什么IIFE能解决因为函数参数是按值传递每轮循环都把当前i的值作为实参传入了函数并保存在词法环境里为什么let能解决因为let声明在每次迭代时都会在块级作用域里创建一个新的绑定每个setTimeout回调通过词法作用域链找到的是各自迭代的那个i。如果只背答案不理解原理面试官换一种考法——比如把var换成const、把setTimeout的延迟时间改成0或者嵌套两层循环——你又会卡住。用友面试官特别喜欢干这种事在笔试题的基础上现场改动一两个条件看你是否真的懂。2.3 typeof和instanceof的边界B端开发天天踩有一类题目表面上考typeof和instanceof实际考的是类型转换和原型链理解的综合能力。比如console.log(typeof null); console.log(typeof []); console.log(typeof function(){}); console.log([] instanceof Array); console.log({} instanceof Object);结果分别是object、object、function、true、true。这里最容易出幺蛾子的是typeof null object这个历史遗留bug以及typeof []返回object但[] instanceof Object也是true的细微语义。更进阶一点还会考var a []; console.log(a instanceof Array); // true console.log(a instanceof Object); // true因为Array.prototype.__proto__ Object.prototype console.log(Object.prototype.toString.call(a)); // [object Array]在这个基础上面试官还可能延伸问你如何准确地判断一个变量是否是数组当年标准做法是Object.prototype.toString.call(arr) [object Array]或者用ES5的Array.isArray(arr)后者在IE9才支持。用友的产品当年还需要兼容IE8/IE9所以这类兼容性判断在笔试里格外受重视。如果你能在卷子上主动写出“考虑到IE8兼容用Object.prototype.toString.call更稳妥”绝对是个加分项。这类题目表面是语法判断实际上在模拟B端开发中的真实需求后端接口返回的数据格式不稳定前端保存单据前必须做类型判断你不能让typeof null object这种坑把整个表单校验逻辑带崩。笔试题不是让面试官看你背了多少API而是看你有没有处理过这些真实的脏数据场景。3. 浏览器与DOM题当年没有框架一切都是原生操作3.1 事件冒泡与捕获从一道点击题聊到事件委托用友的笔试题里事件机制是重头戏。常规考法就是给一段HTML结构注册多个事件让你回答点击之后触发的顺序。div idouter div idinner点击我/div /divdocument.getElementById(outer).addEventListener(click, function() { console.log(outer bubble); }); document.getElementById(inner).addEventListener(click, function() { console.log(inner bubble); }); document.getElementById(outer).addEventListener(click, function() { console.log(outer capture); }, true);当年标准的事件传播顺序是先捕获阶段从window到目标元素再到目标元素本身然后进入冒泡阶段从目标元素逐层回到window。所以上面代码的输出顺序是outer capture→inner bubble→outer bubble。这里最坑的点在于“目标元素本身”不区分捕获还是冒泡谁注册在前谁先执行。很多考生会把inner的事件先冒泡再捕获搞反这一下就丢了分。更重要的是用友这类B端系统的前端大部分场景都是动态渲染的比如审批流的操作按钮、单据明细行的工具栏经常是根据后端数据异步生成HTML。如果每次动态生成都要为每个子元素单独绑定事件内存占用和代码维护成本都很高。因此在真实项目里事件委托是写脚本的常规操作document.getElementById(list).addEventListener(click, function(e) { if (e.target.tagName BUTTON) { var action e.target.getAttribute(data-action); switch (action) { case approve: approveFlow(); break; case reject: rejectFlow(); break; } } });这个模式不仅解决了动态元素绑定问题还天然避免了对内存的浪费。笔试里如果出了“怎么给动态添加的DOM绑定事件”这种题你只要把事件委托方案写清楚基本就是满分答案。我当时准备这类题时给自己定了一个原则凡是出现“动态内容批量操作”“列表渲染后绑定事件”这些场景第一反应就写事件委托绝不直接forEach去addEventListener。3.2 原生DOM操作与属性细节2017年的笔试题几乎没有现在这种“给你一个LeetCode题让你现场写”的套路更多是贴近业务的代码题。比如“给一个表格动态添加一行并绑定删除功能”这种题当年我在考场上是真写过它考察的就是原生DOM操作能力var table document.getElementById(tb); var row table.insertRow(-1); var cell1 row.insertCell(0); var cell2 row.insertCell(1); cell1.innerHTML 张三; cell2.innerHTML button classdel删除/button;然后配合事件委托去处理删除按钮的点击找到按钮所在的tr移出表格。这类题虽然看着“简单”实际上考察了非常多的细节insertRow的参数是行索引-1代表最后一行insertCell的参数是列索引删除时应该table.deleteRow(row.rowIndex)。另一个高频知识点是属性操作与属性读取的区别。比如getAttribute(class)和element.className的区别setAttribute与直接赋值属性的区别以及innerHTML与textContent的选择——在B端系统里经常要渲染后端返回的富文本用innerHTML可能会造成XSS风险因此必须做HTML转义处理。这类题我在笔试试卷里遇到过不止一次它考的不是你能不能写出el.innerHTML p content /p而是你有没有安全意识。用友这类企业软件的页面前端很多时候在加工后端接口返回的数据并拼到DOM里。如果面试者能写出来“用textContent而不是innerHTML来避免XSS注入”的注释那基本就是稳过的答案。我当时在卷子上把这一点写出来之后后续技术面的时候面试官还主动提了一句“我看你笔试里写了XSS处理平时是做这块的吗”——这种细节真的能在茫茫试卷里给人留下印象。3.3 浏览器兼容与B端开发绕不开的IE讲到DOM2017年前端笔试里最绕不开的一个话题就是浏览器兼容。用友当时的典型客户环境是Windows 7 IE11有些政企客户甚至还在用IE9。所以他们的笔试题目里常会出现这类问题“写一段兼容IE8和其他现代浏览器的绑定事件方法。” 这在今天看起来不可思议但在当年是实打实的需求。一个典型的兼容写法是这样function bindEvent(el, type, handler) { if (el.addEventListener) { el.addEventListener(type, handler, false); } else if (el.attachEvent) { el.attachEvent(on type, handler); } else { el[on type] handler; } }再看取消事件冒泡的兼容性function stopBubble(e) { if (e.stopPropagation) { e.stopPropagation(); } else { e.cancelBubble true; // IE } } function preventDefault(e) { if (e.preventDefault) { e.preventDefault(); } else { e.returnValue false; // IE } }这类兼容代码对于经历了那个时代的老前端来说闭着眼都能写。但真正让考生丢分的不是写法本身而是没有意识到为什么要写这么多分支。如果你在卷子上只写el.addEventListener说明你的经验里缺少“线上跑在IE里突然脚本报错导致功能不可用”的痛感。用友笔试题的好处就在于它的题目非常贴近真实项目你答完题基本就能看出自己有没有处理过企业级场景下的兼容问题。4. 从原型链到继承模式这类题的价值不是面试而是日常写代码的底子4.1 原型链考题的常见变体原型链和继承是2017年校招前端笔试的压轴大戏用友也不例外。最常见的考法是下面这种function Animal(name) { this.name name; } Animal.prototype.say function() { console.log(I am this.name); }; function Dog(name, age) { Animal.call(this, name); this.age age; } Dog.prototype new Animal(); Dog.prototype.constructor Dog; Dog.prototype.bark function() { console.log(this.name is barking); }; var dog new Dog(旺财, 3); dog.say(); dog.bark(); console.log(dog.constructor);这里考了几个关键点组合继承的写法构造函数盗用 原型链赋值Dog.prototype.constructor被覆盖后需要重新指回Dog以及dog实例查找say方法时沿着原型链找到Animal.prototype.say的完整过程。输出结果依次是I am 旺财、旺财 is barking、Dog构造函数。笔试题到这里一般还会追加一个思考题“这种继承方式有什么问题”答案是调用了两次Animal构造函数一次是Animal.call(this)一次是new Animal()子类原型上多出来一份无用的name属性。解决办法是用ES5的Object.createDog.prototype Object.create(Animal.prototype); Dog.prototype.constructor Dog;当年如果能在卷面上把两种方案的差异讲清楚等于直接告诉面试官你研究过书上没有的超纲内容这种印象在后续面试中会转化成提问环境里对你的宽容度。现在回头看这些题虽然老但原型链的底层逻辑在面试里考察到今天依然不过时因为这是JavaScript区别于其他语言的根基。4.2 函数式继承与混入更像真实B端场景的写法用友的笔试题有时不直接考“标准继承”而是给你一个业务场景让你想办法实现公共方法的复用。比如多个单据页面都需要“导出Excel”功能你会怎么抽取公共逻辑这种题没有标准答案但一个合格的前端会想到把公共方法放到一个模块对象里再通过混入的方式复制到具体页面对象上比如采用$.extend或者Object.assign。这种设计模式虽然那时不叫“组合优于继承”但本质思路是一致的。所以我在准备用友这类B端企业笔试题时除了刷基本的继承写法还会有意识地把“继承”这件事放到业务复用场景里去思考不只为了继承而继承而是为了减少重复代码、提高维护性。面试官真正想看的不是你会背继承的几种模式而是你在类似“多个页面共用表格导出逻辑”这种场景里能不能设计出清晰的复用方案。4.3 简答题中的设计思路除了代码输出题用友这类笔试还会出开放性的简答题。比如“一个表单页面需要支持编辑和只读两种模式你会怎么设计”这种题没有标准答案考察的是代码组织能力和设计意识。答题时可以从以下角度展开用配置项控制字段权限、用事件驱动切换页面状态、把业务逻辑和视图渲染分层、通过面向对象方式封装表单模型。我当时的态度是这种题最怕只答一两句话答得越具体越显得你有真实项目经验。比如会提到“把每个字段的校验规则写在配置对象里编辑模式下执行校验、只读模式下跳过校验”这就比单纯写“用变量控制”要有说服力得多。用友的面试官也都是做过多年前端的老兵他们看一眼你的回答就知道你是背过书还是真写过代码。5. 数组字符串与排序算法笔试题里的实用主义5.1 数组去重的花样考法数组去重是2017年前端笔试里出镜率极高的一道题用友几乎必考。考察点很明确你至少会一种稳妥的去重方法懂得不同方法的性能差异最好还能写出兼容旧浏览器的版本。最早的常规答案是双重循环去重function unique(arr) { var result []; for (var i 0; i arr.length; i) { for (var j 0; j result.length; j) { if (arr[i] result[j]) { break; } } if (j result.length) { result.push(arr[i]); } } return result; }更轻量高效的是利用对象键值对去重。不过这里有一个经典陷阱如果数组里同时有数字1和字符串1用对象做键会字面量相同导致误去重。当年标准解法是让key带上类型前缀比如typeof item itemfunction unique(arr) { var obj {}, result []; for (var i 0; i arr.length; i) { var key typeof arr[i] arr[i]; if (!obj[key]) { obj[key] true; result.push(arr[i]); } } return result; }再进阶一点用filter加indexOffunction unique(arr) { return arr.filter(function(item, index) { return arr.indexOf(item) index; }); }这个写法的原理是如果某个元素不是第一次出现那么indexOf返回的下标一定小于当前下标于是被filter过滤掉。简洁优雅但时间复杂度是O(n^2)。ES6里可以用[...new Set(arr)]但这个解法在2017年面试时可能还有面试官没听说过如果你能写出来反而是一个优势。笔试题里如果只是让你“写出去重函数”你写完基本函数后再补一句“在大数据量下可以用空间换时间使用查找表法”就足够体现你的性能意识。5.2 字符串与正则的实操题B端系统做表单校验、单据编号解析常常需要处理字符串所以用友笔试题里字符串处理和正则表达式是常客。比如var str hello world; console.log(str.charAt(1)); // e console.log(str.substring(1, 3)); // el console.log(str.substr(1, 3)); // ell console.log(str.slice(0, -1)); // hello worl console.log(str.indexOf(o)); // 4 console.log(str.lastIndexOf(o)); // 7这里的考点是substring和substr的区别、slice对负数的处理以及indexOf找不到时返回-1。不要小看这些细节你的实际开发中天天都会碰到。写错了就是线上bug比如用substr和substring混用导致单据编号截取错位。用友这种负责企业核心单据的系统这种bug影响面非常广绝不是改一行代码那么简单。正则表达式也是必考模块常见的题目有用正则验证手机号、邮箱、身份证号或者提取文本中所有的URL链接。我当时在笔试题里遇到过一个很实际的场景“从一段富文本内容里提取所有图片地址并加上防盗链后缀”这题就是纯粹的字符串和正则基本功var content pimg srchttp://example.com/a.jpg //ppimg srchttp://example.com/b.png //p; var urls content.match(/img[^]*src[\]?([^\ ])[\]?[^]*/g);这里要留意正则的贪婪匹配和非贪婪匹配以及防止把HTML属性引号错误吞掉。能正确写完这个正则且在多种边界条件下不出错的人说明过去真没少处理过富文本编辑器的脏数据。5.3 排序题的“性价比”策略排序算法在校招笔试里属于“高频低难度”类型。用友几乎不会让你去写什么快速排序的极端优化版本更常见的是让你手写冒泡排序或选择排序并说明时间复杂度。这类题虽然编程难度低但却是很多人的送分题变送命题——半天憋不出一个排序函数的也大有人在。当年标准的冒泡排序function bubbleSort(arr) { var len arr.length; for (var i 0; i len - 1; i) { for (var j 0; j len - 1 - i; j) { if (arr[j] arr[j 1]) { var temp arr[j]; arr[j] arr[j 1]; arr[j 1] temp; } } } return arr; }选择排序function selectionSort(arr) { var len arr.length; for (var i 0; i len - 1; i) { var minIndex i; for (var j i 1; j len; j) { if (arr[j] arr[minIndex]) { minIndex j; } } if (minIndex ! i) { var temp arr[i]; arr[i] arr[minIndex]; arr[minIndex] temp; } } return arr; }这两种排序的时间复杂度都是O(n^2)面试官一般不会让你解析它们在数据量到达几十万时的表现——那是大厂算法题干的事。但是你必须在回答里把时间复杂度说清楚并且能举出一个“排序稳定性”的简单例子冒泡排序是稳定的选择排序是不稳定的。有些面试官喜欢追问“这个排序是稳定的吗为什么”能答上来的人不多答上来的人基础都扎实。我的建议是排序题不要只背冒泡最好再顺手准备一个二分查找的写法。B端系统里后端返回的数据很多是无序的前端经常要对其排序特别是按时间倒序、按单号排序这类场景。能熟练手写常见排序和二分查找在笔试和面试现场是一种很舒服的感觉——你会觉得这些题目都似曾相识写起来不慌不忙。6. 代码输出与调试能力笔试题里最隐蔽的“高分项”6.1 为什么代码输出题一定要写分析过程用友的笔试题里代码输出题占的比重很高而且很多是连环问。比如给一段代码先问你输出是什么再问你如何修改达到预期效果最后再问你“在IE下会有什么不同表现”。这种情况下仅仅写对结果是不够的一定要把推导过程写出来。因为阅卷的人不只是看你答得对不对更想从你的推导过程中判断你遇到问题时的排查能力。这是笔试考察的核心价值——企业真正需要的是出了问题能定位的人而不是只会写CRUD的人。我当年在做这道经典题的时候是这么处理的console.log(1 2 2); // 122 console.log(1 2 2); // 32 console.log(A - B 2); // NaN2 console.log(A - B 2); // NaN这类题考察的是JavaScript隐式类型转换的细节。第一行数字1与字符串2相加数字转字符串结果是122。第二行的玄机在 2两个加号之间没有空格第二个加号是一元运算符把字符串2转成数字2于是变成1 2 2前两个数字相加是3再加字符串2结果是32。第三行字符串AB做减法时被转成NaNNaN加字符串2结果是NaN2。第四行NaN加数字2还是NaN。我在卷子上会这样写注释号只要遇到字符串就偏向字符串拼接-号则强制转数字一元可以把字符串转为数字。这套话术简明准确阅卷人一看就知道你懂原理而不是蒙的。这种题在笔试卷里利润率极高答对的基础上再写出分析过程比只写结论多拿一到两分这在分毫必争的校招笔试里非常关键。6.2 模拟断点排查一道经典错题的错误走向用友笔试题有时还会让你当“调试员”给一段有bug的代码让你找出问题并修复。比如下面这段function Counter() { this.count 0; setInterval(function() { this.count; console.log(this.count); }, 1000); } var counter new Counter();这段代码跑起来会发现count打印出来一直是NaN。原因是setInterval里的回调函数是普通函数调用时this指向全局对象浏览器里是window而不是Counter实例。结果就是this.count变成了window.countundefined加1得到NaN。修复方案是把外层的this保存下来function Counter() { var self this; this.count 0; setInterval(function() { self.count; console.log(self.count); }, 1000); }或者用箭头函数ES6function Counter() { this.count 0; setInterval(() { this.count; console.log(this.count); }, 1000); }这类“找bug”的题真正考的不是你能不能背出修复代码而是你遇到问题时会不会打开控制台、打断点、一步步排查this指向问题。用友这类企业的日子天天在和各种老代码里的this指向、异步回调、作用域泄漏搏斗所以面试官非常看重候选人是不是具备这种调试直觉。一个好的调试习惯是遇到这种代码先在浏览器控制台里敲一遍观察实际输出然后思考“为什么是这个结果”再顺着函数的调用方式去查。这个方法比直接背结论要慢一些但它能让你真正掌握这种思维的套路而套路一旦练成以后遇到任何this指向问题你都能秒懂。6.3 异步陷阱setTimeout的延迟执行与事件循环在2017年的笔试题里异步执行顺序是一道必考题。经典题目是console.log(A); setTimeout(function() { console.log(B); }, 0); Promise.resolve().then(function() { console.log(C); }); console.log(D);输出结果是A、D、C、B。原因在于Promise的then回调属于微任务在本次宏任务执行完、当前调用栈清空之后立刻执行而setTimeout即使延迟是0也会被放进任务队列在下一轮宏任务才执行。当年很多考生只背了“setTimeout是异步的”却不知道微任务和宏任务的执行顺序结果这道题拿不到分。用友这类B端系统的前端异步操作遍地都是接口请求、表单校验、文件上传、审批流流转。如果你搞不清异步任务队列的机制写出来的代码很可能出现“明明setTimeout里改了数据、外部拿到的却是旧值”的诡异bug。笔试题出这个就是看你对事件循环的底层理解够不够深。我当时备考时专门把这类题整理成一个专题把宏任务、微任务的执行顺序、Promise和setTimeout的优先关系、async/await的执行时机全梳理了一遍。虽然2017年async/await还没普及但面试官一旦发现你主动提了这个话题基本都会顺着聊下去——这种“自觉超前”的姿态校招生如果能做到真的很加分。7. 从笔试题反推准备方向给准备校招的你的几条通关建议7.1 别死磕“最新潮流”要死磕“语言与浏览器”如果你是现在备考前端校招看到我用友这套2017年的真题可能会觉得“怎么这么老都不考React和Vue”。但我想说的是老牌B端软件厂商的校招笔试历来不追热点只认基础不牢就干不了活的铁律。尤其是在用友这种产品体系庞大、客户环境复杂的企业你的前端代码可能会在客户的IE浏览器里运行你的框架选择可能受制于公司内部底层平台的升级节奏。面试官招人时最怕的就是招一个只会写Vue页面、离开脚手架就不会配webpack的“框架型选手”。所以笔试题目会刻意回归语言本身用最朴素的方式考察你。准备这类企业的校招建议按这样的优先级分配精力第一梯队必拿分变量提升、作用域、闭包、this指向、原型链、Event Loop、隐式类型转换、数组/字符串方法、DOM操作、事件机制第二梯队尽量拿分继承的多种实现、常用设计模式、正则表达式、排序与二分查找、深拷贝/浅拷贝第三梯队拉分项浏览器渲染流程、性能优化的基础思路、常见安全漏洞XSS/CSRF及防范、代码组织模块化你把这个清单捋一遍就会发现它和“用友2017校招web前端笔试题”的覆盖范围高度吻合。当年我在考场上做完题的感觉就是没有一道题是自己没见过或者没练过的剩下的就看熟练度和心态。这种“稳稳拿下大部分分数”的策略比赌面试官出一道你刚好准备过的偏题要靠谱得多。7.2 笔试题答完面试时如何延续优势很多人笔试交卷后就彻底不管了其实这是个失误。用友的技术面试官手里往往会拿着你的笔试卷子不是只看分数而是会挑几道你答得一般的题做追问。如果你能在笔试答题时把推导过程写得清楚、把自己的思考痕迹留下来面试官追问的时候你至少能回忆起来自己当时的思路。怕就怕当时瞎蒙了一个答案面试官一问直接懵。我当时在面试环节就遇到过一个很好玩的追问题笔试里有一道关于数组去重的题我用了查找表法解决面试官问我“你这个方法如果遇到对象怎么办”老实说我当时只考虑了基本类型一下子被问住了。后来我想了想说可以用JSON.stringify把对象序列化之后作为key或者加一个递归比较的深度判断。面试官没有怼我反而说“你能当场想到JSON序列化的方案说明你是真的写过”。这个经历给我的启发是笔试的作用不是证明你全知全能而是给面试官一个和你展开讨论的引子。所以平时练习时不要只追求把答案写对要多琢磨“如果面试官换一个条件来刁难我我该怎么应对”。7.3 实操训练闭卷刷一套题比看十套题解更有用最后给一个非常实用的备考建议找一套完整的老牌企业校招笔试题不一定要用友的金蝶、浪潮、SAP、oracle中国这些B端厂商的题也行给自己定一个严格的时间限制比如90分钟找个安静的环境闭卷完整写一遍。写完之后不要急着对答案先对照自己的卷面思考哪些题是“第一反应就会写的”哪些是“犹豫半天才下笔的”哪些是“完全空白的”。然后针对“犹豫半天”和“完全空白”的部分逐个去翻《JavaScript高级程序设计》对应的章节并且把相关知识点写在一张纸上。这套“做题→发现盲区→补知识点→再做题”的循环效率远高于漫无目的地刷面经。我当年备考用友之前就是用这种模式把JavaScript的六个核心专题反复揉了两遍最后笔试时基本没有遇到知识盲区。8. 回看2017年的前端笔试题当年的题目今天还剩下多少价值用友2017年的这套笔试题放到今天来看确实带了不少时代印记没有ES6模块化的考题、没有webpack配置题、没有React/Vue的组件设计题、没有TypeScript甚至CSS部分也偏基础布局而非flex/grid的细化。但这不代表试题已经过时。恰恰相反它用一种非常“老派”的方式反复敲打着前端入行必备的几根支柱JavaScript语言机制、浏览器运行原理、代码调试思维、面向对象设计能力。这些支柱不管框架怎么换、工具链怎么变都依然是你职业生涯的地基。随着现在前端工程化程度越来越高很多应届生反而出现了“基础弱化”的倾向。你问他Vue的响应式原理他能说一堆但让他解释var a 1; function test(){ console.log(a); var a 2; } test();的输出结果却会卡壳。这就是典型的“用框架遮百丑”。而用友这类企业级软件厂商的面试官恰恰见过太多这种候选人所以他们宁可出一些“看起来不起眼”的基础题去筛掉那些简历写得漂亮但真本事捉襟见肘的人。我在实际带新人的过程中也发现一个规律基础扎实的人学新框架非常快因为他们理解框架本质上是帮你在浏览器环境下做状态管理和DOM操作的工具而底层的this指向、异步调度、原型链查找你该懂还得懂。基础不牢的人则相反换个新框架就换个心智模型每学一个框架都像从零开始。如果你现在还在准备校招我的建议是不要因为题目“老”就轻视你可以不把它当作用友的笔试题来看而是把它当作一个企业级前端工程师的基本功体检单。每一道题都代表着实际项目里一个具体的坑把这些坑填平了你不管去To B还是To C、用React还是Vue都会比别人走得稳。我自己在看完这套题之后最大的感受是2017年和现在的技术栈差别虽然大但前端招聘的底层标准其实越来越清晰——你需要的不是会写页面的“切图仔”而是一个能理解浏览器、理解JavaScript语言、能在复杂业务代码里快速定位问题的工程师。用友的笔试题只是把这个标准用一套朴素的题目表达了出来罢了。