前端面试记

13,174 阅读12分钟

大家好我是前端小白,再记录一些最近面试中的问题吧!此次面试的是一家成都某上市科技企业,先说结果吧,是过了的,话不多说直奔主题。


一、成都某上市科技面试部分(文末有笔试题)

一面

进入上市企业办公区我被拉到一个小房间等待,五味杂陈,像是在演无间道,说时迟那时快,一位漂亮的小姐姐走进来,是的他是我一面面试官(有点意思,第一次遇到小姐姐面试,哈哈嗝~),然后开始了无聊的自我介绍...

1、主要技术栈是Vue是吧,说说双向绑定原理?

通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终
利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化->视图更新。在
初始化vue实例时,遍历data这个对象,给每一个键值对利用Object.definedProperty
对data的键值对新增getset方法,利用了事件监听DOM的机制,让视图去改变数据。

2、用过keep-alive吗,说说对它的理解?

keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,避免重新渲染 ,有以下特性:

1、一般结合路由和动态组件一起使用,用于缓存组件。

2、提供 include 和 exclude 属性,两者都支持字符串或正则表达式, include 表示只有名称匹 配的组件会被缓存,exclude 表示任何名称匹配的组件都不会被缓存 ,其中 exclude 的优先级比 include 高。

3、对应两个钩子函数 activated 和 deactivated ,当组件被激活时,触发钩子函数 activated, 当组件被移除时,触发钩子函数 deactivated。

3、组件中为什么data是一个函数?

data() {
  return {
      message: "123",
   }
 }
 
 原因:因为组件是需要被复用的,所以必须是一个函数,如果是一个对象,作用域没有分开,子组件
 的data属性值会相互影响。是一个函数的话那么每个实例可以维护一份被返回对象的独立的拷贝,组
 件之间的 data 属性值不会互相影响。

4、那为什么new Vue里data可以是一个对象?

new Vue({
  el: '#app',
  router,
  template: '<App/>',
  components: {App}
})

原因:因为JS里的对象是引用关系,而且new Vue是不会被复用的,所以不存在引用对象的问题。

此时我看了一眼小姐姐的眼睛,她若有所思的看着我的简历(心里想这家伙不像一年多 经验呀,难道是是在装嫩?)

5、一道程序题,小姐姐在我简历背面写出来的

var a=?;
if(a==1&&a==2&&a==3){
     console.log('小样儿!');
 }
 
 问:当a等于什么的时候,if条件成立,并打印?

我从小姐姐的眼神里看出了一丝得意,心想不会了吧?傻眼了吧?哇哈哈哈...

我以迅雷不及掩耳之势快速写完,而且还附赠另一种方法(因为我见过这道经典题嘻嘻嘻),小姐姐坐不住了...

应该大家和我一样,刚刚看到这题的时候,确实觉得匪夷所思,感觉不符合程序的逻辑,下面我就 剖析一下这题

猜想:

刚开始看到第一眼这个题,我的想法是让 a=true 或者 a=!0 应该可以,拿起键盘就是干。

由此可以看出,代码世界的奇妙我还没有悟到......

正解:

一:利用对象的类型装换

var a={
    num:1,
    toString:function(){
       return a.num++;
    }
  }
 if(a==1&&a==2&&a==3){
     console.log("恭喜答对啦!");
 }else{
     console.log("还是错了小子!");
 }

原理:

a==1&&a==2&&a==3,这是一个短路逻辑与运算符,表示左边条件为真时才会继续往右判断,否则立即整个判断像短路一样,所以 a 的第一个值必须是 a==1 为真才会继续向右判断 a==2,由此可以推断出 a 的值或者说是转换类型后的值是可以自增长的,JavaScript中当遇到不同类型的值进行比较时,会根据类型转换规则试图将它们转为同一个类型再比较。比如 Object 类型与 Number 类型进行比较时,Object 类型会转换为 Number 类型。转换为时会尝试调用 Object.valueOf 和 Object.toString 来获取对应的数字基本类型。

在上面代码中,逻辑转换先调用了valueOf方法,如果返回的还是对象,再接着调用toString()方法。每次比较都会先执行重写后的对象方法toString(),这个方法里先返回属性num的值再自增。执行a==1判断时,对象a调用toString()方法返回了属性num的值1,此时比较两个当然是相等的。与此类似,a==2和a==3一样成立。怎么样是不是很巧妙?

二:利用数组的取值和类型转换

var a=[1,2,3,4];
a.join=a.shift;
 if(a==1&&a==2&&a==3){
     console.log("恭喜答对啦!");
 }else{
     console.log("还是错了小子!");
 }

原理:

乍一看,这个方法是不是优雅了许多?一个字 ,那么他是怎么做到了呢,原因是我们都晓得JavaScript中一切皆对象,那么Array也是对象的后代类,他也继承了Obj的valueOf()和toString(),而且重写了toString()方法。全部抬起小脑袋,请看这句话 a.join=a.shift, 他的意思是当数组调用toString()方法而间接调用join方法时,shift()方法替代了join方法,这样就相当于每次从a数组中截取第一个元素返回。所以当判断a==1时其实是从原数组截取了第一个元素的值返回后再判断,这样原数组就变成了[2,3,4]了,接着a==2判断执行类似操作以此类推,怎么样是不是挺巧妙!(还有很多方法可实现,自行查阅)。

二面

小姐姐思量了一会儿,我猜不透她的心思,起身说,您稍等一会儿,等下主管来二面... 不一会儿,一阵清晰的高跟鞋的声音循序渐进...推门进来的又是一位小姐姐,一面小姐姐也跟着进来了,What??? 这.这..我要进这家公司当时就一个念头(想啥呢..哈哈开玩笑的,我是经得起考验的人)

又是按计划进行的自我介绍...

六、说说三次握手四次挥手呗?(必考)

握手:(模拟甲请乙吃饭,我是这么理解的)

1、客户端发送一个SYN码给服务器,要求建立数据连接;(甲:来我家吃饭,给你一张SYN门卡)
2、服务器拿到SYN和自己处理一个SYN(标志);叫SYN+ACK(确认包);发送给客户端,可以建立连接;(乙:我收到你的门卡了,我也给你一张叫ASK的卡)
3、客户端再次发送ACK向服务器,服务器验证ACK没有问题,则建立起连接;(甲:来了啊进来吧!乙:出示你的ASK卡,我看看走错没,甲:这不是吗?快进来吧)

挥手:

1、客户端发送FIN(结束)报文,通知服务器数据已经传输完毕;(甲:小声嘀咕..这货吃完了吧?该走了吧)
2、务器接收到之后,通知客户端我收到了FIN,发送ACK(确认)给客户端,数据还没有传输完成(乙:我听到你说的话了,你确定赶我走吗?但是我还没吃完哎!)
3、服务器已经传输完毕,再次发送FIN通知客户端,数据已经传输完毕(乙:我吃完了,别解释了,果然不爱了,我走了)
4、客户端再次发送ACK,进入TIME_WAIT状态;服务器和客户端关闭连接;(甲:把你的ACK还给你,把我家米都吃空了)

不行了,写到这儿我已经笑得没力气了...但是我觉得对于我们这种来说,感觉更直观,更通俗易懂,要是全都是一些专业术语可能半天理解不了。大佬们请别嫌幼稚,单纯为了一些刚入门不久的同学写的。

七、为什么建立连接是三次握手,而断开连接是四次挥手呢?

建立连接的时候, 服务器在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个
报文里发送给客户端。而关闭连接时,服务器收到对方的FIN报文时,仅仅表示对方不再发送数据了
但是还能接收数据,而自己也未必全部数据都发送给对方了,所以己方可以立即关闭,也可以发送一
些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分
开发送,从而导致多了一次。

八、map和forEach的区别?

相同点:
都是循环遍历数组中的每一项,forEach和map方法里每次执行匿名函数都支持3个参数,参数分别是
item(当前每一项)、index(索引值)、arr(原数组),需要用哪个的时候就写哪个,匿名函数
中的this都是指向window,只能遍历数组。
不同:
map方法返回一个新的数组,数组中的元素为原始数组调用函数处理后的值。(原数组进行处理之后
对应的一个新的数组),map()方法不会改变原始数组map()方法不会对空数组进行检测forEach()
方法用于调用数组的每个元素,将元素传给回调函数.(没有return,返回值是undefined,forEach
对于空数组是不会调用回调函数的。)

九、说说原型和原型链?

原型:
把所有的对象共用的属性全部放在堆内存的一个对象中(共用属性组成的对象),然后让每一个对象的
__proto__存储这个(共用属性组成的对象)的地址。而这个共用属性就是原型。原型出现的目的就是
为了减少不必要的内存消耗。
原型链:
而原型链就是对象通过__proto__向当前实例所属类的原型上查找属性或方法的机制,如果找到Object
的原型上还是没有找到想要的属性或者是方法则查找结束,最终会返回undefined,终点是null

十、从输入url地址到页面相应都发生了什么?

这个问题涉及太广了,得分几个方面回答,这里请看三元老哥的(1.6w字)浏览器灵魂之问,请问你能接得住几个?

十一、做过单点登录吗?了解他是怎么实现的吗?

实话实说没做过,但我看过一些关于单点登录的技术博客,大概整理原理如下:

概念:
简称为 SSO,是目前比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,
用户只需要登录一次就可以访问所有相互信任的应用系统。

列如:淘宝、天猫都属于阿里旗下的产品,当用户登录淘宝后,再打开天猫,系统便自动帮用户
登录了天猫,这种就是用单点登录实现的。
流程:
1、用户访问A系统,系统A发现用户未登录,跳转至sso认证中心,并把自己的地址作为参数。
2、sso认证中心发现用户未登录,则引导用户到登录页面。
3、用户输入用户名和密码提交登录。
4、sso认证中心验证用户信息,创建用户->sso之间的会话(全局会话),同时创建授权令牌。
5、sso认证中心带着令牌跳转到A系统
6、系统A拿到令牌,去sso认证中心校验令牌是否有效。
7、sso认证中心校验令牌,返回有效,注册系统A8、系统A使用该令牌创建与用户的会话(局部会话),返回请求资源。
9、用户访问系统B10、系统B发现用户未登录,跳转至sso认证中心,也将自己的地址作为参数。
11、sso认证中心发现用户已登录,跳转到系统B,并附上令牌。
12、系统B拿到令牌,去sso认证中心校验令牌是否有效。
13、sso认证中心校验令牌,返回有效,注册系统B14、系统B使用该令牌创建与用户的局部会话,返回请求资源。
注意:
1、局部会话存在,全局会话一定存在
2、全局会话存在,局部会话不一定存在
3、全局会话销毁,局部会话必须销毁

十二、浏览器渲染的主要流程是什么?

html代码按照深度优先遍历来生成DOM树。css文件下载完后也会进行渲染,生成相应的CSSOM。
当所有的css文件下载完且所有的CSSOM构建结束后,就会和DOM一起生成Render Tree。接下来,
浏览器就会进入Layout环节,将所有的节点位置计算出来。最后,通过Painting环节将所有的节
点内容呈现到屏幕上。

然后问了一些项目问题,接下来三面是老板面,让我没想到的是还是个女的,后来了解到公司前端组刚刚成立,共五人,四个小姐姐(哇咔咔咔...),老板了解了一下我的背景和经历,就谈了下薪资,聊得还不错,薪资我也满意,最后可惜啊!上市公司的入职果真麻烦,说大概要走三周左右,本人又刚刚从深圳转战成都,可能等不了那么久,所以最后给拒了(很是心疼...)

笔试题

这些题我也是花了半小时,全部写完了的,小伙伴们可以试一试!