编者按: 对于开发者来说, 找工作最难的莫过于技术面试 Fredrik Strand Oseberg 在 freeCodeCamp 上发表了一篇文章, 介绍了自己学习编程 6 个月后找工作获得 5 个 offer 的经历文章由 36 氪编译
我先给大家介绍一下我的工作背景
在过去的 6 个月里, 我一直在孜孜不倦地研究我的投资组合和个人项目 最值得注意的是, 我创建了 CryptoDasher , 这是一种能够实时跟踪加密货币和投资组合价值的工具 我还参加了一家名为 Loopring 的中国区块链公司举办的设计竞赛
我觉得已经准备好了 我向挪威一家大型咨询公司投了简历, 应聘其前端开发人员的工作, 并引起了他们的注意至少我是这么认为的
通过笔试和第一轮面试后, 我被邀请参加技术面试这是最重要的一个环节
我很紧张
你应该怎们准备这个技术面试呢? 我问自己 我四处询问, 疯狂地在互联网上搜索相关资料 并在 YouTube 上看了一些模拟面试 以下是我使用的一些资源:
拆解前端面试 (freeCodeCamp 上的文章)
David Shariff 的 2017 年为 web 前端开发面试做准备
每个 JavaScript 开发者都应该知道的 10 个面试问题
Toptal 的 JavaScript 面试问题列表
Mozilla 开发者网络(MDN)
Pramp - 与其他人进行模拟面试的工具
Github 前端开发者问题合集
YouTube JS 模拟面试 1
YouTube JS 模拟面试 2
我在这些材料上花了好几个小时的时间, 尽力为即将到来的面试做好准备 如果我在面试前没有尽最大的努力, 我会感到很不舒服, 我相信你明白那种感受
面试的那天到了 我早上 4 点就醒了
很害怕, 很好奇, 也很兴奋
我在公司的大厅里遇到了面试官, 和他一起去了他们的办公室
我们之间的交谈很愉快, 并相互交换了联系方式 我比较擅长软技能, 所以我希望能早点展示这种能力很快, 我又见到了 另一位面试官, 然后去了会议室
面试刚开始很顺利 我们每个人都进行了自我介绍, 他们开始问我一些关于我的背景的问题
他们问我, 开始学习编程时, 最困难的部分是什么, 我想学习什么样的技术, 我想要教别人什么技术, 以及我觉得令人兴奋的东西
在这一点上, 我觉得面试很顺利我很想知道更多关于这家公司的信息, 我觉得已经与面试官在某些方面有了共鸣
然后技术部分开始了
首先, 我被要求解释我在笔试中的代码是一个 为数据集创建分页, 并将其显示在列表中的任务 我用 React 编写了它, 然后我开始检查代码 当我们浏览这些代码时, 我的面试官会问我一些问题 我将试着把他们提出的问题列出来, 以及给出我认为的面试官想要的答案
你知道单元测试是什么吗? 代码的哪一部分可以进行单元测试?
说实话, 我想我回答错了 单元测试是一段代码, 用于验证一个单元或源代码的特定部分是否执行了它的预期目的, 而不会产生不必要的副作用 我不记得我说了什么, 但我可能把它和集成测试混在一起了 在面试之前, 我确实对单元测试和 TDD 有一定的了解, 但在这种程度上, 可能已经超出了我的理解范畴
在进行了一些讨论之后, 我得出结论: 我可以对分页函数进行测试, 因为它对程序中的大部分逻辑负责
你将如何改进这个项目?
我发现这个问题有点令人困惑 当我完成笔试 (几周前) 时, 我就被要求列出一份关于该项目的改进清单 假设面试官已经知道了这些, 我就很难找到什么改进空间了
我很快就明白了, 面试官对我在电子邮件中提到的事情很感兴趣, 于是我开始提到这些点错误处理移动优化 Ajax 调用加载时的用户反馈以及大型数据集的页面管理
你知道 BEM 是什么吗? 你在代码中使用的是 BEM 吗?
我回答说我知道 BEM 是什么 这是一个用于 CSS 项目的命名约定, 代表 BlockElementModifier 我还回答说, 在我的 CSS 类命名中, 我受到了 BEM 的启发, 但它并不完全是 BEM, 因为它没有遵循所有的 BEM 规则
你如何使这个网站更具移动友好度?
CSS 媒体查询 这是最主要的一个 他们想知道, 我是否知道如何利用媒体查询来让网站做出响应
到目前为止面试进展 很好 我觉得我很完整地回答了这些问题, 尽管我需要在了解面试官的具体想问什么之前, 先讨论一下这些问题
编程挑战
然后他们要求我扩展功能 我被要求实现一种排序机制, 该机制将采用分页数据集, 并根据名称和编号对它们进行重新排列 我有几分钟时间来思考这个问题
我问了一些问题, 比如我是否应该使用内置的 JavaScript 排序函数, 或者构建自己的函数 (稍后我们会看到, 这是一个很大的错误) 分页数据以对象数组的形式存在, 其中每个对象都有一个包含 20 个对象的数据数组, 这些对象代表列表中的每一个项目 我提出了以下的算法:
1 将每个分页对象数据数组合并到一个新的数组中;
2 对新数组进行排序;
3 对排序后的数组进行分页, 并将组件的状态设置为新近排序的数组
这是一个很好的算法 我很快就知道该怎么做了 现在唯一的问题是实施它 这就是我犯错的地方
首先, 我花了很长时间来找出如何组合这些数组 我承认, 这种情况给我带来了一些压力 因为我本可以用一个简单的 reduce 来解决它的时候, 我做了各种奇怪的事情 公平地说, 我当时并不像现在这样熟悉 reduce
- // 我应该做的
- const pageData = pages.reduce((startingValue,page)=> startingValue.concat(page.data),[])
- // 我最终做的
- const pages = this.state.pages; const pageData = [];pages.forEach(page => pageData = pageData.concat(page.data));
现在我有了一个包含所有数据的数组, 我需要编写逻辑来对其进行排序 由于我在编程方面的经验, 在很大程度上是基于我自己构建的项目, 所以我花了很长时间来处理 JavaScript 排序函数 我必须要查资料, 所以, 我花了一些时间来检查 MDN 和 stack overflow 上的例子, 以便我在实现它之前真正理解它
我只是部分地完成了分拣工作, 我被困在这里好一段时间 数组中的大多数名称都是正确排序的, 但是在顶部有一些名称是无序的 在这个时候上, 我试图保持冷静, 但在我的脑海里, 已经崩溃了 我想要知道为什么它没有正确排序 我被困在这里的时间比我想承认的要长
经过面试官的讨论和督促 我最终想起来了字符串是按照它们的 ASCII 值排序的 大写字母的值是 65-90, 小写字母的值是 97-122 没有正确排序的结果有一个大写的首字母, 它具有先排序的效果, 因为它们的 ASCII 值比小写字母要低这是一个我永远不会再犯的错误
当找到问题后, 我立即用用. toLowerCase()解决了这个问题
现在只剩下一件事了
将已排序的数据传递到分页函数中
在这里, 我遇到了一个麻烦
分页函数需要一个 Ajax 响应, 并将每一项传递给一个 formatData 函数, 该函数提取相关片段并返回一个新对象 然而, 当我试图传递被排序的数据到这个函数的新数组时, 它将不再具有原来的属性名, 并且函数会给出一个错误
我花了一些时间研究这个问题, 然后我才发现我必须将 formatData 从分页函数中移出, 并在数据传递给分页函数之前在响应数据上执行它
完成了这些工作, 并进行了一些更小的修改, 代码终于可以工作了虽然 花了一些时间, 但最终我解决了
此时, 技术面试的编程部分结束了
我感到精疲力竭
我们最后又聊了一会儿, 然后结束了面试在结束之前, 我问题一些问题, 他们告诉了我更多关于他们公司的事情
然而, 面试并没有就此止步
我仔细复盘了这次面试, 琢磨我做错了什么
第二天, 我花了三个小时来改进解决方案, 然后我发了这封邮件:
嗨, 面试 X 和面试官 y
我想感谢你们昨天同意和我交流我已经思考了很多关于这个问题的解决方案, 我决定今天就改进它我提供了我们昨天工作的增强版本的代码这是我所做的:
我扩展了排序功能, 以便能够在第二次按下时逆转结果
我将分类功能扩展到所有的 titles
我添加了一些图标来对 titles 进行排序
我重构了分页函数, 学习了单元测试的基础知识, 并使用 Jest 来测试它的功能
我增加了对分页的查询字符串支持, 这样重载和链接就会在访问不同的页面时显示正确的数据
我添加了媒体查询样式, 使组件更具移动友好度
在 API 调用发生时, 我添加了一个加载器
我添加了错误处理, 让用户有机会重新启动 API 调用
我在移动设备上改变了排序功能, 并使用了一个选择框
......
这可能有点矫枉过正, 但我很受启发, 我想要改进解决方案
最好的问候,
Fredrik Strand Oseberg
这还不够 但至少我尽了最大的努力 过了一段时间, 我收到了这封邮件:
嗨!
我们想感谢你的面试, 但我们必须得出这样的结论: 我们不能给你这个职位的 offer, 因为你在技术方面没有达到我们的期望
我们喜欢你的背景, 相信你能很好地融入我们的社区, 所以我们在你的技术面试中给了你一份详细的反馈, 希望你能在获得更多编程经验后再申请我们的职位
我在哪里出错了?
幸运的是, 我得到了一份详细的反馈报告 让我们来看看吧, 我将和你们讨论其中的内容
反馈 1: 花费太多的时间来了解如何组合数组 首先在互联网上搜索, 而不是检查 JavaScript 文档(例如: js array doc 将提供 w3schools 或 MDN, 其中列出了函数), 并错误地使用了这些示例(array.concat 返回一个新数组) 没有人会记住 API 中的所有内容, 所以能够很好地使用 JS 或库的文档是很重要的
要点: 面试官希望你首先接触到 MDN(或其他相关文档) 他们希望看到你能够找到并阅读文档, 并根据发现的信息来实施它
反馈 2: 在排序分配中, 候选人首先提出了一个奇怪的手动算法 幸运的是, 他选择在 JavaScript 中使用内置的排序功能, 但是不确定它是如何工作的, 并且必须反复检查文档
要点: 在交流中要绝对清楚 在这种情况下, 我询问了面试官关于我是否应该使用内置的 JavaScript 排序功能, 以搞清楚手头上任务的界限和限制 不幸的是, 我认为这被误解为我建议自己使用的排序算法
这最终产生了和我想要传达的相反的效果 确保你清楚地表达出你的问题想要澄清的东西 因为它们可能对你来说很有意义, 但你的面试官可能会对此有所察觉
反馈 3: 当代码运行时, 文本被排序为区分大小写 不幸的是, 候选人花了很长时间才明白这个问题, 但一旦被发现, 就立即改了过来
要点: 速度是最重要的 在编写程序时, 总是会出现 bug, 但是要尽可能快地解决它们 找到问题的根源, 如果你不知道, 就迅速地去查文档
反馈 4: 花了一些时间来理解为什么要在重构的时候将 formatData 移出分页
再说一遍, 速度是最重要的
反馈 5: 许多 foreach 循环, 其中可以用数组. map 或 array.reduce 来解决 了解更多函数式编程将是有益的
要点: 学习数组. maparray.filter 和 array.reduce, 并熟练地掌握它们 我一直在钻研函数式编程, 这是一项艰巨的任务 但是你现在不需要完全精通这些知识, 只要确保你能掌握了基础知识就行
反馈 6: 我希望候选人对单元测试有更多的了解
要点: 这似乎是显而易见的, 但重要的问题要多说几遍: 测试很重要 测试很重要 测试很重要 学习它 使用它
这份文件的其余部分都是赞扬 我不会说太多细节, 因为它没那么重要 要点是:
他很好地使用了编辑器
他在 Chrome 中使用调试器(了解高级调试工具很重要)
在继续工作之前, 他会检查这些东西是否正常工作(使用 console.log)
他试图将代码分成更小的逻辑部分
他使用变量名而不是注释, 这使得代码可读性更好
他很了解 React
之前的项目令人印象深刻
拥有编程之外 (设计 / 视觉) 其他积极的品质
在准备过程中, 我还能做些什么?
当你被拒绝的时候, 你将不可避免地花费一些时间来思考你可以做些什么不同的事情
更彻底地检查笔试代码
我花了太多时间研究我的 JavaScript 知识 我应该更了解我自己的代码 尽管我写了这篇文章, 但在写作和面试之间的几周时间里, 你需要回顾一下 我希望我在这上面花的时间比在模糊的 JavaScript 问题上更多
做更多实操性的 JavaScript 任务
在面试前我做了很多理论工作 我现在希望我能够花更多的时间做更多的实际工作, 或者至少是混合了一些实际的工作, 或者构建一些常见的前端组件, 比如排序列表下拉菜单分页等等
面试结束
在第一次技术面试结束后我感觉如何? 老实说, 这是一次很棒的经历 我非常感谢面试官, 他们给了我如此详细的反馈, 让我能够在下一次面试前纠正我的错误 尽管我没有得到这份工作, 但我离成为第一个前端开发者的工作又近了一步
我也了解到面试是一件反复无常的事情 也许如果我在自己的项目中构建了一个排序机制, 或者如果我得到的是一个与我之前完成的任务更接近的任务, 面试结果将会有所不同
我最大的优势是在过去的一年中我花了很多时间学习 JavaScript, 现在我能够很快地学习和采纳新的想法 不幸的是, 我这次没有能力证明这一点
通往成功之路
现在, 我很容易对自己说: 我还不够好 我需要花 3-4 个月的时间来学习, 然后再试一次
但我没有
我决定在两周内尽可能多的申请工作 我向挪威最大的 IT 公司投递了简历
两周后, 我完成了几家公司的初步面试, 然后我又接受了技术面试
第二轮准备
我在第一次技术面试中学到的一件事是, 准备工作很关键 它可以帮助你把技术面试变成是一场考试, 并采取必要的步骤来确保你通过考试
但将考试比作面试是错误的, 因为它没有涵盖候选人的全部知识范围 那你能做什么呢?
扩大你的知识范围
我使用了先进的记忆策略, 在 8 个小时内记住了超过 100 个面试问题的答案 这些问题可以在这个数据库中找到
此外, 我还在在 Code Wars 和 Hackerrank 的 实例上花了很多时间并花了很多时间来构建一些事物
第二次技术面试
我在上次失败的面试中吸取了很多教训, 我做了很多的准备
这次面试的重点是讨论前端概念 这是一次全面的面试, 我觉得面试官想搞清楚我的知识范围, 并弄清楚我的强项和弱项
这次面试持续了大约两个小时 以下是我们所讨论的所有主题的列表:
JS,CSS 和 html 概述
文档结构
项目结构
Git
性能
安全
可访问性
搜索引擎优化
响应式网页设计
编程挑战是基于 vanilla Javascript 的 我被要求用普通的 Javascript 将一个简单的类添加到一个 div 中 现在, 如果你已经花时间用 JS 来使用主要的框架, 你可能不熟悉 classList API 幸运的是, 我大部分时间都花在了所有的 freeCodeCamp 项目上 这就是它的样子:
const btn = document.querySelector('.btn'); const menu = document.querySelector('.menu');function addClassNameToDiv() { if (!menu.classList.contains('new-class')) { menu.classList.add('new-class'); } else { menu.classList.remove('new-class'); }} btn.addEventListener('click', addClassNameToDiv)
或者, 您可以使用 classList.toggle('new class')将其转换为一行程序 如果你点击下拉菜单, 我还被要求将它扩展至关闭菜单:
window.addEventListener('click', () => menu.classList.remove('new-class'));
从编程挑战中获得的信息是:
越短越好, 只要它总是可读的
在性能方面, 最好将查询选择器置于事件监听器回调函数之外(只调用一次, 而不是每次都触发)
性能方面, getElementById 和 getElementByClassName 比 querySelector 更好
第二天, 我接到了经理的电话 我通过了面试, 他们想给我一个机会 我本可以在这里停下来, 不用参加其他的面试了 我可以说: 我已经拿到了一个 offer, 这已经足够了
但我做了相反的事情
我打电话给所有我正在面试的公司, 并告诉他们我已经收到了一个 offer, 并问他们是否可以加快进程, 因为我现在有时间限制
面试, 尤其是技术面试, 都是很艰难的心理考验如果 你一直在展示, 面试官将期待你的表现能够超越预期 这很难 那么我为什么要这么做呢?
原因有四个
1 我想向自己证明, 这不是运气
2 我想要尊重每一个给我面试机会的人, 给他们一个公平的机会
3 我想确保自己找到了适合自己的公司, 让我成为一名开发人员
4 为了你们, 这个社区对我的帮助很大, 我想从技术面试中获得尽可能多的信息, 这样你们就可以从我的错误中吸取教训, 并做出相应的准备
我对我从 freeCodeCamp 获得的帮助和支持感到惭愧, 我想要回报
第三次技术面试
在与其他公司取得联系, 并表明我获得了一家顶级公司的 offer 后, 很多公司都迫不及待地想让我通过面试 在一周内, 我完成了几次技术面试
以下是第三次技术面试中的一些问题:
你是如何学习 React 的? 你为什么要学习它? 这有什么好处?
Redux 是如何工作的? 这个 API 由什么组成的? 什么是不变性? 不变性的好处是什么?
你将如何重新设计我们的网页?
你如何处理更深层次的应用程序? 例如后端?
你自己做测试吗? 什么是单元测试?
对你来说, 什么是好的用户体验?
如何测试用户体验?
这次面试中的编程挑战是基于 CSS 的
我收到了一张纸, 上面有一些 CSS 规则, 看起来是这样的:
<div id="menu" class="dropdown-menu"></div> // HTML Element // CSS Rules #menu { color: black; }.dropdown-menu { color: green; }div { color: blue; }
我的任务是解释我所看到的 我立即识别了了 HTML Element 并告诉面试官, element 上的 id 和 class 可以在 CSS 中使用, 以选择 HTML Element 在这里, 我解释说 CSS 是级联的, 这意味着通常最后一条规则将适用 然而, 在这种情况下, 选择器有不同的权重顺序如下所示: id> class>element
这意味着, 在上面的示例中, 黑色将被应用到 HTML Element 中
第四次技术面试
这是我进行的最后一次技术面试 虽然它仍然很伤脑筋, 但现在我已经习惯了 下面是我们讨论的内容:
建立一个基本的网站 确定其中的组件
你如何让它响应?
如何将文本垂直和水平居中?
什么是 CSS 框模型? 内容框和边框之间的区别是什么?
React 有什么好处?
array.forEach 在 for 循环中的好处是什么? 有没有可能需要使用 for 循环的情况?
编程挑战是建立一个不同程度难度的 wordwrap 函数 想象一下, 你只能在屏幕上放 20 个字符, 如果你超过它, 你就得从一个新行开始
我对这个问题的原始解决方案涉及拆分字符串, 使用计数器和模数运算符来确定计数是否为 20, 然后在数组中插入一个换行符并加入字符串
然后, 任务难度增加了, 只允许全部单词排成一行 也就是说, 如果一个单词导致总数超过 20, 那么需要在单词前面插入一个换行符
我在面试中并没有完全解决这个问题, 但我的思路是正确的 在我不确定的时候, 我使用了 MDN, 并且我取得了很好的进展
这就足够了
我不能把它写下来, 如果你感兴趣的话, 这里有一个解决的版本:
function wordWrap(str) { let totalCount = 0; const arr = str.split(''), formattedStr = []; arr.forEach((word, index) => { totalCount += word.length; if (totalCount >= 20) { formattedStr.push('\\n', word,' '); totalCount = word.length; } else { formattedStr.push(word,' '); } }); return formattedStr.join(''); }
结论
如果看到了这里, 恭喜你 这是一个漫长的过程我尽可能提供更多的信息, 希望它能帮助像你这样的人
这样做的结果是, 我陷入了一个我从未想过的境地 最后, 我有 5 个 offer 可供选择 一家大公司甚至给我提供了一个 blindoffer, 不管竞争对手给我多少钱, 它都能更高 我最终选择了我第一次通过技术面试的公司, 因为我相信这对我来说是最合适的
技术面试可能是一场艰苦的精神折磨 你会受到挑战, 你会被带出你的舒适区, 这是一件好事 它能帮助你成长 它会让你变得更好
如果你准备好了, 你就能有所收获
所以从我的经验来看, 不要回避技术面试 不要因为你失败了就放弃 不要认为这是你作为开发者的终极衡量标准 它不是 它只是公司用来衡量你的生产力的最简单的工具
申请工作 准备好 参加技术面试 从错误中学习不断 重复这一过程
如果你这样做, 我保证你会成功
来源: http://www.tuicool.com/articles/2eI3EjA