某银行前端一年半经验进字节面经

3,075 阅读11分钟

19年毕业进入到某银行,年底转正,给的offer是前端开发,但是由于所在中心主要职责是数据方面的开发,只能边干前端边学习数据开发的知识,后期前端的内容越来越少,于是在有内推机会的情况下,工作之余复习加面试,成功拿下offer,记录一下面试过程。

一面

1. 高阶组件是什么?你设计这么一个水印组件,为什么用高阶组件。组件设计思路。

答:HOC定义,一个函数,接受一个组件返回一个包装后的组件。该问题是因为简历上有写自己的玩具项目(水印组件Github地址)。实现原理很简单,内部是一个第三方的水印组件,但是我需要兼容React项目中的使用,但又不想破坏其内部代码结构,那么最好的办法就是增强其功能让它支持配置的透传以及兼容React代码,在这种需求下我们可以利用HOC,配置项的传递可以继续在HOC之上再抽象一层,即:

const WatermarkEnhancer = optionsObject => metaComponent => enhancedComponent
// 可以配合装饰器使用
@WatermarkEnhancer({
  ...options
})
class Demo extends Component {
    // some code
}

2. 说一下水印组件的业务场景。如果有人要在控制台里通过删除dom的方式去除水印,怎么防范?

答:可以说一下MutationObserver,监听dom变动重新加上水印;监听键盘事件F12禁止打开控制台;假设用户在控制台中通过disable js来禁用js,监听事件无效了,又该怎么防范?(说了一下思路,比如点击disable js这个动作本身是可以监听到的,那么可以监听这个动作并且拦截,然后可以做一些自定义的操作,比如直接关闭掉页面)

3. Dvajs和Umijs区别。

答: Dvajs本身其实约等于redux + react-redux + redux-saga,它整合了同步异步状态的管理,并做出了一些约定,让开发者可以根据套路很方便的管理状态,又因为它的底层只是上述几个库的整合,API也高度保持一致,所以上手门槛非常低(如果你本来就了解使用过redux、redux-saga的话)。简单把Dvajs理解为一个同步异步状态管理的最佳实践即可。

再来看UmijsUmijs的定位是一个框架,其内部整合了Dvajs(状态管理)、Router(路由功能)、request(网络请求)、Mock(本地开发的接口mock功能)...该框架囊括了这些功能,实际上起到了一个技术收敛的作用,只需一个Umijs,把开发需要的功能基本包含,而不需要自己装一堆玩意儿还得去配置。

4. Dvajs中redux用处(展开聊聊状态管理的必要性和合理使用不滥用的思考)

答:简单说一下React里的单向数据流,组件状态的管理,父传子,子传父,跨组件层级传递。公共状态比较适合Redux进行统一管理(useContext也可以)。但是如果本身就自己组件内部管理、独立的状态则不适合提出来,这样会让组件复用变得困难,不仅要处理组件还需要处理redux,切记不要滥用。如果你目前不知道为啥要用redux等状态管理库,那就是你现在并不需要它,等你觉得有必要用的时候它自然会出现。

5. React和redux是独立的,怎么关联起来使用(react-redux中的connect和provider作用)

答:实际上redux本身是框架无关的,它只是制定了一套流程便于我们管理状态,良好的状态流转和修改状态的步骤让我们更容易管理复杂状态,而如何结合到React里则是react-redux需要做的工作,它起到桥接作用,一端连接React、一端连接Redux,这也是为什么它的名字叫react-redux,涉及到的API不赘述了查一下文档即可。

6. react-redux的性能问题(?)

答:直接和面试官表示没怎么遇到过性能问题(可能就是我太菜了没达到这个程度)

7. this指向问题(箭头函数定义时确定,普通函数执行时确定)

class Student {
  constructor(name) {
    this.name = 'Tom'
  }

  getInfo() {
    return {
      name: 'Jerry',
      getName() {
        return this.name
      }
    }
  }
}
let s = new Student()
console.log(s.getInfo().getName()) // Jerry
// 如何打印出Tom,只能修改class中代码(箭头函数,展开说一下this指向的问题)

8. obj实例化,修改属性和重新实例化的指针问题

function changeObjProperty(o) {
  o.siteUrl= 'http://a.com'
  o = new Object()
  o.siteUrl = 'http://b.com'
}

let s = new Object()
changeObjProperty(s)
console.log(s.siteUrl)

9. 0.1 + 0.2 !== 0.3(精度丢失问题:IEEE 754。如何解决?比如按小数点拆分整数部分与小数部分,分别按位相加,注意进位处理。)

10. 简述一下SPA与前端路由(扩展讲一下ajax -> pjax -> history api的pushState, popState, replaceState。浏览器url的出栈入栈与这些api的关系,路由映射管理与组件渲染。)

11. 编码:

/* 
实现一个randomString函数,返回一个数组,该数组内有一千个字符串,每串字符串为6位数0-9的随机验证码,不可重复。
*/
function randomString() {
//  write your code here
}


12. 编码:

/*
实现一个sum函数,接收一个arr,累加arr的项,只能使用add方法,该方法接收两个数,模拟异步请求后端返回一个相加后的值
*/
function add(a,b) {
  return Promise.resolve(a+b)
}

function sum(arr) {
  // 思路可以二分,切成两部分beforeSum, afterSum。
}

/*
变种:如果后端设置了并发限制,一次不能请求超过三个,怎么办?
*/

二面

1. css题:实现一个chrome浏览器的后退按钮,鼠标移入有深色的圆形背景,内部是一个90度的角。

2. 需求题:假设有A页面有一些query参数 点击打开B页面 要把A的参数带过去 然后B页面跳转到C页面 如果是B页面本身带的参数 就带到C页面 如果B页面的参数是A页面带过来的 那么就不带到C页面。(这一题基本花去了大部分时间,和面试官讨论了可行的思路,然后进行编码。主要是query参数的merge处理,跳转拦截之类的实现。)

3. 常规题:把123456789,变成金钱模式,即:12,345,678(思路有很多,比如reverse之后利用模除手动插入逗号...)

4. 简历相关的内容不在这里记录了。

三面

1. 编码题:

/*
请实现抽奖函数rand,保证随机性
输入为表示对象数组,对象有属性n表示人名,w表示权重
随机返回一个中奖人名,中奖概率和w成正比
*/
let peoples = [
  {n:'p1', w:100},
  {n:'p2', w:200},
  {n:'p3', w:1}
];
let rand = function (p) {
};

2. 开放题:一个html引入一个超大JS,js中是一个乱序数字数组(长度巨大),从中找到最大值显示出来,遇到这种需求你该怎么做?

3. 项目相关的问题不在这里记录了。

三轮技术面其实可以感觉出来一面会考察一些前端基础和源码相关的知识,二面三面还会问很多项目经验、管理方面的内容。比如git工作流、CI/CD相关实践、重构的一些思考、选型的影响因素、自己平时学习的方式。因为我在银行里还会进行数据开发以及会一点node开发,这些也算是加分项吧。

HR面

个人感觉hr面其实会带有一些博弈的成分,但是和hr聊天,尽量真诚就行,工作本来就是双方互相选择的,在目前公司的现状以及与自己职业规划产生的偏差,自己的期望发展、待遇其实可以真诚的说出来。最终字节给的待遇是令我感到满意的,我也很开心可以到更好的平台发展。(毕竟银行的技术底蕴确实没法和字节比,还是需要一个更好的平台提升自己,光靠自己实在不太行...)

感想

记得是三月底开始,那时候个人遭受了比较大的打击,工作也浑浑噩噩的,看不到出路,每天晚上失眠,白天工作状态也不好,还吃不下东西。字节那边联系过来问有没有时间面试,我就说了个日子开始面试了。就这样强迫自己开始看资料查漏补缺,心里反倒好受了一点。

还记得是那一个周日,窗外阳光很好,我和一面面试官聊了一个多小时。感觉氛围很轻松,有编程题但是确实难度不会高,边读题边把思路和面试官说了,然后开始编码。问的一些内容基本都可以答上,面试官每次听我说完就会点头然后说一句“好的,没问题。恩恩。我们看下一个。”我很感谢他让我久违地感受到,交流技术的愉悦。一面的末尾我问了一些职业规划的问题,他也很耐心的和我说了一些自己的经验,最后很感谢我可以在周末抽出时间面试。

一面的结果很快就出来了,当晚hr和我说的时候我其实还不太敢相信。因为我从毕业前就有尝试过投大厂,但是无一例外全部都是一轮游,我深深地怀疑自己的能力是否确实与这些大厂的岗位不匹配。毕业了进入银行其实也有点像逃避。接下来我和hr约定了下一轮面试的时间,并决定抛开那些不愉快的回忆,工作之余把全部精力投入到二面的准备中去。

然后我和之前实习时候带我的启蒙老师聊到我过了字节的一面,她还是像以往那样对我的求助耐心解答,也给了我一些资料让我查漏补缺。后来我又在github翻到了字节这边的同学编写的一份前端面试资料。时间一天天过去,这段时间的专注让我想起了那个高三,很明确的目标与每天的工作、加班、复习,出乎意料的让我心情很平静。

二面的时候,面试官对我说的第一句话就是“一面面试官对你的评价很不错,希望你继续努力。”。二面其实问了很多简历上的项目,包括一些实现细节,还有项目的使用场景、解决的痛点与技术实现上的难点。看得出来面试官也在尝试尽可能深入了解我以前做的东西,讨论过程中也不断提出了一些问题。而后就是一些常规的题,上面面经里写的那个路由跳转拦截传参的问题,面试官应该是考察我的编码能力,这道题应该花去了四十几分钟的时间,不断的提出自己的问题明确需求,不断的提出自己的思路讨论可行性,然后尝试编码。

其实我对二面的表现并不满意,忐忑地等待结果,最终还是等来了三面。三面前问了很多本来就在字节的同学,也在那时候加了昊神微信,到了宇宙条小分队,群里到处都是大佬,每天都能学到新东西,可开心了!

三面的面试官可能所处层次不一样,不太喜欢我说话的时候讲的太细或者举具体的例子,希望我说话可以简练、抽象。面试过程中被打断了好几次发言,让我不要展开讲很多,总结就可以了。编码题一直在和面试官讨论,因为当时真的一点思路都没有,当时就感觉这次是不是凉掉了... ...好在最后还是勉强写出来了,不过被说代码太复杂了。开放题如上面面经,还问了很多比较抽象的问题,感觉偏管理一些。

最后等来hr面的时候我突然感觉,我没自己想象中的差劲。和hr聊了现在的工作,以后的规划还有期望得到的待遇。之后走流程和hrbp谈妥薪资,拿到offer之后我和现在的领导聊了聊。其实我还是不太习惯离别,他问我要走的原因,和现在有哪些不满意的地方,然后恭喜我可以到更大的,技术底蕴更深的公司去。目前我在整理手头上的工作,交接完之后就要搬离这个待了快两年的地方,开始一段新的生活了。其实一个人在外漂泊,从一个地方到另一个地方,遇见一些人,告别一些人或者成为被告别的人。总是需要不停的想一想,这条路我想要通到哪儿。

祝愿大家都获得让自己满意的offer!