2018.04.18
首先,我先说说整个过程吧。(如果对过程不感兴趣的话可以直接拉到下面的面试题)
笔试(我觉得考的稀烂,以为没有面试机会的)结束后大概一周,下来了面试通知,下午三点半。
我从我们大学提前一个半小时从实验室出发的,到目的地的时候差不多2:50分了,三点的时候我找到了会议中心一楼,然后进去看到大厅两旁都有工作人员在长桌面前坐着,一部分是答疑指引方向,一部分负责签到啥的等等,我去到签到的地方问工作人员,那个男士貌似有点不耐烦的跟我说扫码签到就好了。我觉得奇怪,人长的挺帅的,但是服务态度怎么这么差呢?但是我扫码之后我还是道了声谢谢,最起码的礼仪还是要得,然后又继续问他,然后该怎么办,他说进去会议厅找个位置等着就好了,微信公众号会提示你面试的具体厅号和桌号。
然后,我就走进了会议厅,尼玛!吓屎劳资了!我特么还以为进错地方了!只见我抬头看到了好几把多的人,几乎坐满了整个厅的2/3了!关键是那个厅很大!能坐估计四百人!我在想一个实习生面试怎么搞的像人才市场一样啊?后来还是想想,人家是顶级互联网公司,只有这个规模才能配得上吧。
随后,等了不到十分钟,就轮到我了...怀着忐忑的心情去到了我所在的面试官位置。
好,开始正题。
面试官:你是xx(姓名)对吧?
我:是的,是的,前辈您好。
面试官:好,先做个自我介绍吧?(第一个问题)
我:(...由于紧张,头脑开始空白,不知道自我介绍从哪说起,随后觉得这样不行,就深吸了一口气说道)您好,我是吧啦吧啦......我平常的时间除了科研论文之外,剩余的时间基本上都用来学习前端了(骗子!才没有呢!其实我前两天准备的自我介绍中准备还说我偶尔运动放松一下,但是到现场之后由于紧张忘记了!)。我学习前端总共有这么几种方式(我之前准备的有七种):
第一种,看书。看过的书有《js高级程序设计第三版》、《web性能指南》等;
第二种:看技术博客。常去的有csdn、博客园等;
第三种:做笔试题和面试题。因为每当自己遇到不懂的或者不会做的,就会去谷歌搜索;
第四种:自己写博客总结。写博客有助于我对前端知识体系的理解,记录自己的成长;
第五种:通过实习学习。在实习中,通过实践可以更加深入的理解理论,而不是停留在表面。
漏掉的两种:
1)和同学们(都搞前端)交流。因为通过这种分享与讨论的方式可以更加巩固知识和加深对知识的理解;
2)通过线上资源。网上有很多的前端网络资源,比如像慕课网、极客学院、腾讯课堂等,上面的资源都比较优质。
面试官(看了看我的简历):那你说说你做项目的时候都用了哪些基础知识?(第二个问题)
我:(...我勒个去!这个问题尼玛把我问懵了...我该怎么回答?好像没用到啥基础知识啊...我支支吾吾了十几秒,实在挤不出啥话可以回答的,那时我就想,我得引导面试官才行,就说)用到的有面向对象设计、继承啥的。(我擦!这尼玛叫回答?而且项目中根本没用到好不好?惭愧啊!)
面试官:那好,你说说继承吧?(第三个问题)
我:继承的方式有六种(js高级程序设计里讲的),有原型链、组合继承、寄生式继承、继承组合式继承。(漏掉了两种,1)借用构造函数;2)原型式继承)程序员最常用的是组合式继承。
面试官:那你写一个继承吧。(第四个问题)
我(只能凭借看书的记忆写下代码):代码如下
function Person(){
this.name = 'Charles',
this.age = 24,
this.sayName = function(){
console.log(this.name);
}
}
Person.prototype.sayHello = function(){
console.log('hello');
}
var Person1 = new Person;
Person1.name = 'Tom';
Person1.sayName();//Tom
console.log(Person1.age);//24
Person1.sayHello();//hello
我原本是打算这样写的,也知道这个原理。但是很遗憾,由于紧张,把Person1.sayName()的值给写成Charles了,擦。真的是在面试中不能紧张啊!只有冷静才能帮你清醒思路。(PS:这是原型链继承,跟我说的组合继承关系并不大,大写的尴尬...)要想把相关知识都复习一遍,可以参考链接:点击打开链接
面试官(看了一眼就放在一边了....):跟我说一说闭包吧。(第五个问题)
我:闭包的概念是能有权访问其他函数内的变量的函数。(我看了面试官一眼,从他的表情上来看这个答案并不合他的意)由于闭包可以称作是函数内的函数,由于js在执行闭包外的函数时,闭包会缓存外部函数的作用域,所以在执行完外部函数之后,外部函数内的变量并不会立刻销毁,故闭包才可以访问到外部函数内的变量。
面试官:你的意思是内部函数能访问到外部函数内的变量,那外部函数是不能访问内部函数的变量的是吗?
我:是的。
面试官:那有没有一种方法或者是方式可以实现外部函数能访问到内部函数内的变量呢?(第六个问题)
我(我擦,完了,这个问题我不会怎么办?):让我好好想一想,您可以借我一张纸吗?(马德,现在的我真的好想打屎我自己,装什么逼啊,还特么要张纸!不会就是不会)在纸上描绘了半天后,回答:不知道....
面试官:那我们跳过这个问题吧。
我:那您能不能告诉我可以实现的一个方法呢?
面试官:可以在里面创建一个匿名函数,在匿名函数里面返回需要的变量。
我:噢~~~(装作懂了的样子)
面试官:现在有一个实时更新的数据,要把这个数据展示在页面,你怎么实现?(第七个问题)
我:可以使用setInterval方法,每隔一段时间就更新一次数据。但是我觉得setInterval这个方法不太好,比较耗性能,不可取。我再想想看有没有其他的方法可以实现。
面试官:嗯,你说的setInterval方法的确可以实现,也确实存在着你说的缺点。
我(支支吾吾了半天):可以通过for循环遍历的形式吗?
面试官:你说的遍历好像也只能遍历当时某一刻的数据,并不是实时更新的数据
我(考虑到请求最好只有一次,于是联想到了数组):那可不可以像弹幕那样,每出来一个新的数据就把原先第一个数据给删除掉,屏幕上显示的弹幕总个数是固定的,遵循先进先出的原则。
面试官:你这个想法只是对数据的处理,我的问题是怎么显示实时更新的数据
我(窝草,居然带不偏):这个我暂时想不出什么办法了。
面试官:那你得下去自己好好了解下了,跳过这个问题吧。用户从地址输入栏输入网址回车到页面展示的这个过程都发生了什么?(第八个问题)
我(我勒个去!我之前在别人的博客上看到了这个题目的解答过程,但是今天特么的忘记了!悔死了!):我尝试着说下我自己的理解。首先是用将网址输入后,然后回车,浏览器把要发送的数据和头部发送给服务器...然后...想不出来了。
面试官(皱了皱眉,表示不满意):既然这样的话,那我们跳过吧。
我:我之前有在博客上看到过,可能当时有些过程不太理解,所以对这整个过程的记忆不太清楚,理解的也不太清楚。
面试官(笑了笑):你下去好好了解下吧。那你跟我谈谈事件委托吧。(第九个问题)
我(我再次无语,因为这个问题我之前也是在网上了解过,又特么忘了!):给同属于一类标签元素添加一个click方法,就比如有十个li标签,按照传统的方式的话,是给每个标签都加上一个onclick事件方法,但是这样比较耗资源,事件委托就可以解决类似的事情。但是具体怎么实现,我想想...摇了摇头说暂时无法得知。
面试官(他又说了这一句话):你自己下去好好了解吧。那你跟我说说浏览器缓存的问题吧,一般来说,用户在请求一个文件的时候,如果浏览器缓存里面有会从缓存里取,这样就不用请求数据到服务器了。这个原理是怎么实现的?浏览器是怎么判断其缓存里是否有用户请求的文件,具体怎么实现的?(第十问)
我(心里一首凉凉送给自己):这个方面我没了解过。
面试官:没了解是吧?那好吧,我这边暂时没什么问题了,你有什么问题要问我的吗?(第十一问)
我:您面了我这么些时间,也知道我的能力所在,您是否有啥针对性建议我之后的学习呢?就比如我始终对前台和后端之间的联系不太清楚,后台的服务器怎么搭建,前台通过什么方式去取数据。
面试官:你可以自己搭建一个个人网站,自己亲手编程实践,从实践中你就可以更加深入理解了。
我:好的,谢谢前辈。
完~~~
面试题:
一、自我介绍
二、做项目的时候用到了哪些基础知识?
三、说说继承并写一个继承代码
四、谈谈闭包
五、有没有一种方法或者是方式可以实现外部函数能访问到内部函数内的变量呢?
六、现在有一个实时更新的数据,要把这个数据展示在页面,你怎么实现?
七、用户从地址输入栏输入网址回车到页面展示的这个过程都发生了什么?
八、谈谈事件委托
九、那你跟我说说浏览器缓存的问题吧,一般来说,用户在请求一个文件的时候,如果浏览器缓存里面有会从缓存里取,这样就不用请求数据到服务器了。这个原理是怎么实现的?浏览器是怎么判断其缓存里是否有用户请求的文件,具体怎么实现的?
十、你有什么问题要问我的吗?
下面是我回去后自己整理的答案(1、2、10这是大家自己该做的准备,这里不赘述):
三、说说继承并写一个继承代码
答:继承主要是依靠原型链来实现的。最常用的是组合继承(借用构造函数和原型链组合继承),继承的方式还有原型式继承、借用构造函数继承、寄生式继承、寄生组合式继承。其次实现继承还可以通过call()和apply()方法,call()和apply()方法是将this指向转变成它们的第一个参数对象。
代码实例:
function Parent(){//构造函数Parent
this.name = 'daddy';
}
Parent.prototype.sayName = function(){//构造函数Parent的原型对象上的方法sayName
return this.name;
}
function Child(){//构造函数Child
this.name = 'son';
}
Child.prototype = new Parent();//构造函数Child的原型对象是Parent
var parent = new Parent();//parent是构造函数Parent的一个实例
var child = new Child();//child是构造函数Child的一个实例
console.log(parent.sayName());//daddy,首先查找自身,没有sayName方法,就在其原型对象上查找到了并调用
console.log(child.sayName());//son,自身没有sayName方法,就去原型对象上查找,它的原型对象是Parent,发现也没有,就在Parent的原型对象上查找到了
这里面试官有可能会追问call()和apply()的使用方法和作用(参考链接:点击打开链接)
四、谈谈闭包
答:js高级程序设计第三版中给出的概念是:闭包是有权访问其他函数内部变量的函数。
当你给出这个答案之后,你自己都会觉得这句话不足以让面试官满意,所以你还得进一步说明为什么闭包能有权访问其他函数内的变量呢?。
追答:由于在js中,变量作用域属于函数作用域,在函数执行后作用域就会被清理,内存也随之回收,但是由于闭包是建立在函数内部的子函数,它可访问上级作用域(可理解为闭包缓存了上级作用域),即使在外部函数执行完之后,外部函数的作用域也不会随之销毁(也就是其内部变量的值也不会销毁),这时闭包就拥有了访问上级作用域中变量的权限。
但是,你还要做好准备,因为可能面试官会进一步追问。有可能他会问,闭包解决了什么?
答:在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。由于闭包可以缓存上级作用域,那么就使得函数外部打破了“函数作用域”的束缚,可以访问函数内部的变量。以平时使用的ajax成功回调为例,这里其实就是一个闭包,由于上述的特性,回调就拥有了整个上级作用域的访问和操作能力,提高了极大的便利。开发者不用写钩子函数来操作上级作用域内部的变量了。
进一步可能会追问的问题,闭包有哪些应用场景?
答:闭包随处可见,一个ajax请求的成功回调,一个事件绑定的回调方法,一个setTimeout的延时回调,或者一个函数内部返回另一个匿名函数,这些都是闭包。简而言之,无论使用何种方式对函数类型的值进行传递,当函数在别处被调用时都有闭包的身影。
刚才举的例子是不是感觉好熟悉?有点像js异步回调里的知识点(参考链接:点击打开链接和点击打开链接)
五、有没有一种方法或者是方式可以实现外部函数能访问到内部函数内的变量呢?
答:可以在函数内部创建一个闭包,在闭包内声明一个变量,这个变量的值可以是静值也可以动态变化,然后将该变量返回。最后在闭包外部,也就是外部函数的内部将闭包返回即可实现。
代码实现如下:
var bar = (function(){
//这里可以声明外部函数的变量
var foo = function (){
var name = 'biubiu';
return name;
}
})();
console.log(bar());//biubiu
六、现在有一个实时更新的数据,要把这个数据展示在页面,你怎么实现?
答:(摘自知乎上的回答,链接:点击打开链接)
1,ajax短连接:客户端每隔一秒钟发一次请求,服务器收到请求后会立刻返回结果,不管有没有新数据。
2,ajax长连接:客户端发送一次请求,服务器端收到请求后查询有没有新数据,如果没有新数据就阻塞这个请求,直到有新数据或者超时为止。客户端每次收到请求返回结果后立刻再发一次请求。comet貌似就是这个原理。
3,WebSocket:这就不是一个HTTP协议了,而是一个tcp协议,而且Socket这个玩意顾名思义就是一个流了,可以双向操作。要想对webSocket有具体的了解,可以参考阮神的博客,链接:点击打开链接
对比延迟:
假设网络延迟是m毫秒,那么ajax短连接的延迟在m到1000毫秒之间,另外两种基本只有m毫秒的延迟。
对比资源占用:
应该是1>2>3。但是1和2的比较要看情况,如果两次请求间隔时间很长的话应该是2>1>3。
另外还有node.js的http://socket.io也可以实现。其次,回答完问题之后要随时对面试官接下来的问题做好准备,因为他可能会追问关于ajax和WebSocket的相关知识。
七、用户从地址输入栏输入网址回车到页面展示的这个过程都发生了什么?
答:这里摘自一篇博客,链接:点击打开链接,不过可能一些概念没讲清楚,我个人推荐这篇博客:点击打开链接
对于网址栏的URL不同的操作方式有不同的加载资源、获取数据的方式,下面的详细过程针对"在地址栏输入URL,按enter(回车)键加载资源"此种操作方式做解析,其它的方式的过程大同小异,差异会在后面再做分析。
1. 浏览器开启一个线程来处理这个请求,对URL判断如果是http协议就按照web方式处理;
2. 浏览器先查看浏览器缓存-系统缓存-路由器缓存,如果缓存中有,会直接在屏幕中显示页面内容(此时没有向服务端发请求)。若没有,则进行下一步操作(后面需要向服务端发送请求);
3. 通过DNS解析获取网址的IP地址;
4. 向真实IP地址服务器发起tcp连接,与浏览器建立tcp三次握手。
5. 握手成功后,进行HTTP协议会话,浏览器发送报头(请求报头);
6. 进入到web服务器上的 Web Server,如 Apache、Tomcat、Node.JS 等服务器;
7. 进入部署好的后端应用,如 PHP、Java、JavaScript、Python 等,找到对应的请求处理;
8. 处理结束回馈报头,将数据返回至浏览器;
9. 浏览器开始下载html文档(响应报头,状态码200),同时设置缓存;
10. 之后浏览器对整个 HTML 结构进行解析,形成 DOM 树;与此同时,它还需要对相应的 CSS 文件进行解析,形成 CSS 树(CSSOM)。
接下来,需要结合 DOM + CSSOM,形成一个绘制树(Render Tree);
11. 得到绘制树之后,需要计算每个结点在页面中的位置,这一个过程称为layout ;
12. layout的过程是在一个连续的二维平面上进行的,接下来,需要将这些结果栅格化,映射到屏幕的离散二维平面上,这一过
程称为 paint ; 现代浏览器为提升性能,将页面划分多个 layer,各自进行 paint 然后组合成一个页面(composite layers)。
PS: 开头说到的"对于网址栏的URL不同的操作方式有不同的加载资源、获取数据的方式"中其他方式的过程与上面方式差不多,只是在处理缓存这一环节上有些不同:
1. “转至”或地址栏里回车刷新:见上
2. F5刷新:没有第2步,在第8步判断返回值,如果返回304则表示有缓存,且此时直接用缓存;如果返回200则表示没有缓存,顺序执行至最后
3. Ctrl+F5刷新网页的区别:没有第2步,且在第8步一定返回200并顺序执行至最后
(对于以上3种不同方式更好的应该从http协议的缓存机制上做区分更容易理解,此处更侧重'向服务端发送请求及其返回值'这方面做一下区别)
八、谈谈事件委托
答:对“事件处理程序过多”问题的解决方案就是事件委托。事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。举个例子就是假如我要实现分别点击十个不同的li标签显示不同的信息,按照传统的做法就是给每个li标签添加一个事件处理程序,这样很消耗资源,而且容易出现“空事件处理程序”,因为可能在某个时候会删除某个li标签,那么对应的事件处理程序就是为空的,但是它依旧占用了资源,有可能无法被视作垃圾进行回收。所以,这个时候利用事件委托就可以解决上面出现的问题。
根据不同面试官,他们的要求不一样。有的面试官会听你的理论解说是否有力,有的则是偏重你的代码能力。
代码实现:
HTML部分:
<ul id = 'mylists'>
<li id='list-1'>go somewhere</li>
<li id='list-2'>do something</li>
<li id='list-3'>say some words</li>
</ul>
JS部分:
var list = document.getElementById('mylists');
list.addEventListener("click",function(e){
if(e.target && e.target.nodeName == 'LI'){
console.log('list',e.target.id.replace('list-',''),'was clicked!');
}
});
注意:在项目中使用事件委托的时候,建议父级盒子不要给固定宽度,推荐由子元素撑开父级盒子,因为事件委托是由冒泡的原理实现的,所以,如果给父级定了固定宽度,那么点击空白部分也是能够触发点击事件的,且e.target.id(或其他形式)是没有值的,没有值的话,多数情况下代码是无法走下去的。
九、那你跟我说说浏览器缓存的问题吧,一般来说,用户在请求一个文件的时候,如果浏览器缓存里面有会从缓存里取,这样就不用请求数据到服务器了。这个原理是怎么实现的?浏览器是怎么判断其缓存里是否有用户请求的文件,具体怎么实现的?
在回答之前,我先说说这个问题到底怎么答。这个问题你(如果你没有对这方面的了解)起初听完后会有点懵,面试官到底想从你身上获取什么信息呢?是浏览器缓存机制还是刚才后面追加的问题?很明显的是,这题不管是缓存机制和后面追加的问题,你都要答。但是不管怎么说,这个问题你想答个七七八八,我想一个实习生的实力是很难做到的,这不是短时间内就能完全理解的知识点。
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
补:
2018.11.04
现在回想起来,那时的自己真的不知道哪来的勇气去面试腾讯,啥都不知道,很多基础的知识点都不知道,比如常见的事件委托和http缓存,但也正因为去了才知道自己是多么的菜鸡!
再来补充下秋招电面腾讯的问题(我笔试都没过,只是后期有个部门招人就又把我的简历捡起来了,又虐我一遍,这次是真的"死透了"...):
秋招(问题不分顺序)
一、自我介绍
二、你实习的时候项目使用的技术栈是什么?有用过react么?react和vue的区别是什么?
三、http缓存
四、TCP和UDP的区别
五、有了解过promise吗?能说说它的原理是什么吗?
六、有了解过预加载和懒加载么?它们的原理是什么?
七、node有了解吗?
八、js去重数组有哪些方法?利用对象属性去除的方法有什么弊病?
九、如果后台一次性给你返回上万条数据,你怎么进行处理才使得浏览器性能保持良好渲染?
十、async和await的原理是什么?
十一、7:15在一个挂钟上面显示,时钟和分钟的夹角是多少度?
十二、let和const的区别是什么?const创建一个对象之后为什么还能修改其内的方法?它创建的原理是什么?
十三、有使用过打包工具么?gulp的工作原理是什么?
十四、先有一个工作日志系统(可跟踪开发人员的代码使用率)需要你设计,你怎么设计?
十五、有了解过现在前端的一些前沿技术么?
十六、DNS的查询步骤有哪些?
十七、判断一个数据是否是数组的方法有哪些?
至此,此次的面经分享完毕。总的来说,大公司的面试官要求应聘者的基础知识牢固且知识体系广。对于各个岗位的知识掌握度比较熟悉,而且一个常面的面试题在网上有很多,除开js高级程序设计第三版书中的各个内容,齐次就是网络优化和安全的问题。这两大类考察的知识最多。其次就是你简历上写的项目经验和实习经历,不管怎么说,面经毕竟是别人的,自己获取面经的经验最佳途径都是去面试,不要怕,在面试中成长是最快的,也很容易找到自己的不足之处。
现拿到三个offer,都是白菜价,结束了长达三个月的秋招,曾面试到一度否定自己,但是还是要保持好良好的心态,与君共勉。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
再更...
2018.11.23(没听清是哪个部门,反正在北京,腾讯体量太大了,到处在招人,当然了,我反正不优秀...)
一、js事件机制(浏览器在解析js文件具体是怎么样的?浏览器怎么判定异步请求任务的顺序?)
二、Promise、async和await
三、你怎么设计封装一个类似于Jquery的ajax请求?对于web要求的token机制你怎么拿到后台返回给你的token和怎么判断你拿到了?
四、浏览器具体是怎么解析一个HTML模板的?解析时行内样式会不会构成重绘和阻塞?
五、你在项目中有用到过哪些设计模式或自己研究过?
六、你在实习的过程中哪个项目你最骄傲或者哪个技术难道你攻克了?
七、你常用的js库是什么?说说vue的一些组件啊,UI啊等,你怎么理解并应用到项目中的?
八、说一说原型链和继承?
九、说说setTimeout和setInterval。