一面:(1h)
1.自我介绍
2.介绍一下你在项目中遇到的困难
我说了在首页轮播图中使用mockjs模拟数据,轮播图用的是swiper组件,但在new Swiper实例之前由于页面中的结构不完整无法出现轮播图效果。在mounted中new实例,因为放在这里所以结构不完整。然后我讲了我寻找解决问题的过程,和如何逐步去优化。说了最终最佳选择的方法就是watch+nextTick
(其实说项目难点的时候你不用考虑说去整理一个多么高大上的东西,面试官想听到的是你在做项目的一个思考的过程)
3.你刚刚提到了nextTick能说一下它的原理吗?
Vue 在更新 DOM 时是异步执行的,在修改数据后,视图不会立刻更新,而是等同一事件循环中的所有数据变化完成之后,再统一进行视图更新。所以修改完数据,立即在方法中获取DOM,获取的仍然是未修改的DOM。
$nextTick的作用是:该方法中的代码会在当前渲染完成后执行,就解决了异步渲染获取不到更新后DOM的问题了。
$nextTick的原理:$nextTick本质是返回一个Promise
应用场景:在钩子函数created()里面想要获取操作Dom,把操作DOM的方法放在$nextTick中
4.能说一下你简历上写的数据懒加载和首页缓存优化吗?
数据懒加载:我说了一下我用js去判断 后台调用接口的条件 和 滚动条的处理
首页缓存优化:这里我提到了keepalive
5.能说一下keepalive吗
作用:缓存组件,提升性能,避免重复加载一些不需要经常变动且内容较多的组件。
<keep-alive>使用方法:使用<keep-alive>标签对需要缓存的组件进行包裹,默认情况下被<keep-alive>标签包裹的组件都会进行缓存,区分被包裹的组件是否缓存有两种方法:
1.第一种是给keepalive 添加属性,组件名称指的是具体组件添加的name,不是路由里面的name。include 包含的组件(可以为字符串,数组,以及正则表达式,只有匹配的组件会被缓存)。exclude 排除的组件(以为字符串,数组,以及正则表达式,任何匹配的组件都不会被缓存)。
2.第二种也是最常用的一种是,和路由配合使用:在路由中添加meta属性。 使用keepalive导致组件不重新加载,也就不会重新执行生命周期的函数,如果要解决这个问题,就需要两个属性进入时触发:activated 退出时触发:deactivated
6.登录操作是你实现的吗?登录时token放在哪里?
token可以放在cookie中。
token一般是用来判断用户是否登录的,它内部包含的信息有:uid(用户唯一的身份标识)、time(当前时间的时间戳)、sign(签名,token 的前几位以哈希算法压缩成的一定长度的十六进制字符串)
token可以存放在Cookie中,token是否过期,应该由后端来判断,不该前端来判断,所以token存储在cookie中只要不设置cookie的过期时间就ok了,如果 token 失效,就让后端在接口中返回固定的状态表示token 失效,需要重新登录,再重新登录的时候,重新设置 cookie中的 token 就行。
7.可以说一下cookie和localstorage的区别吗?
(这时候你可以去说一下cookie 、sessionStorage 、localStorage 他们三者的区别。分别从数据存储位置、生命周期、存储大小、写入方式、数据共享、发送请求时是否携带、应用场景去描述。)
Cookie、SessionStorage、 LocalStorage都是浏览器的本地存储。 它们的共同点:都是存储在浏览器本地的 它们的区别:cookie是由服务器端写入的,而SessionStorage、 LocalStorage都是由前端写入的,cookie的生命周期是由服务器端在写入的时候就设置好的,LocalStorage是写入就一直存在,除非手动清除,SessionStorage是页面关闭的时候就会自动清除。cookie的存储空间比较小大概4KB,SessionStorage、 LocalStorage存储空间比较大,大概5M。Cookie、SessionStorage、 LocalStorage数据共享都遵循同源原则,SessionStorage还限制必须是同一个页面。在前端给后端发送请求的时候会自动携带Cookie中的数据,但是SessionStorage、 LocalStorage不会。应用场景:Cookie一般用于存储登录验证信息SessionID或者token,LocalStorage常用于存储不易变动的数据,减轻服务器的压力,SessionStorage可以用来检测用户是否是刷新进入页面,如音乐播放器恢复播放进度条的功能。
8.如何实现可过期的localstorage?
localStorage只能用于长久保存整个网站的数据,保存的数据没有过期时间,直到手动去删除。所以要实现可过期的localStorage缓存的中重点就是:如何清理过期的缓存。 目前有两种方法,一种是惰性删除,另一种是定时删除。 惰性删除是指某个键值过期后,该键值不会被马上删除,而是等到下次被使用的时候,才会被检查到过期,此时才能得到删除。实现方法是,存储的数据类型是个对象,该对象有两个key,一个是要存储的value值,另一个是当前时间。获取数据的时候,拿到存储的时间和当前时间做对比,如果超过过期时间就清除Cookie。 定时删除是指,每隔一段时间执行一次删除操作,并通过限制删除操作执行的次数和频率,来减少删除操作对CPU的长期占用。另一方面定时删除也有效的减少了因惰性删除带来的对localStorage空间的浪费。实现过程,获取所有设置过期时间的key判断是否过期,过期就存储到数组中,遍历数组,每隔1S(固定时间)删除5个(固定个数),直到把数组中的key从localstorage中全部删除。 LocalStorage清空应用场景:token存储在LocalStorage中,要清空
9.说下跨域
这里我没想起来,说成core了,面试官脸色一下就不好了,艾玛吓死我了,还好之后纠正了。
首先说什么是跨域,要提到同源协议,然后说跨域的几种解决方式:说了cors、node中间件、JSONP,知道有postmessage也可以解决(不知道的小伙伴快自己去学一下跨域的知识,这个问题面试官问到的频率还是蛮高的,几乎我每场面试都有被问到)
10.生命周期
(这个答案我不写了,我之前看b站一老师说过,他当面试官这要是说不上来的话直接秒挂,最基本的知识点)
11.可以说下数据类型有哪几种
8种!!Number、String、Boolean、BigInt、Symbol、Null、Undefined、Object、8种
JS数据类型分为两类:一类是基本数据类型,也叫简单数据类型,包含7种类型,分别是Number 、String、Boolean、BigInt、Symbol、Null、Undefined。另一类是引用数据类型也叫复杂数据类型,通常用Object代表,普通对象,数组,正则,日期,Math数学函数都属于Object。
数据分成两大类的本质区别:基本数据类型和引用数据类型它们在内存中的存储方式不同。
基本数据类型是直接存储在栈中的简单数据段,占据空间小,属于被频繁使用的数据。
引用数据类型是存储在堆内存中,占据空间大。引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址,当解释器寻找引用值时,会检索其在栈中的地址,取得地址后从堆中获得实体。
12.如何判断number的数据类型呢?
(这里考的是判断数据类型的4种方式,可以说你用了什么方法去判断)
JavaScript有4种方法判断变量的类型,分别是typeof、instanceof、Object.prototype.toString.call()(对象原型链判断方法)、 constructor (用于引用数据类型)
typeof:常用于判断基本数据类型,对于引用数据类型除了function返回’function‘,其余全部返回’object'。
instanceof:主要用于区分引用数据类型,检测方法是检测的类型在当前实例的原型链上,用其检测出来的结果都是true,不太适合用于简单数据类型的检测,检测过程繁琐且对于简单数据类型中的undefined, null, symbol检测不出来。
constructor:用于检测引用数据类型,检测方法是获取实例的构造函数判断和某个类是否相同,如果相同就说明该数据是符合那个数据类型的,这种方法不会把原型链上的其他类也加入进来,避免了原型链的干扰。
Object.prototype.toString.call():适用于所有类型的判断检测,检测方法是Object.prototype.toString.call(数据) 返回的是该数据类型的字符串。 这四种判断数据类型的方法中,各种数据类型都能检测且检测精准的就是Object.prototype.toString.call()这种方法。
可以使用typeof去判断,使用Object.prototype.toString.call()方法更加精准。Object.prototype.toString.call()的原理就是Object.prototype.toString 表示一个返回对象类型的字符串,call()方法可以改变this的指向,那么把Object.prototype.toString()方法指向不同的数据类型上面,返回不同的结果
13.你刚刚提到了this,能说一下改变this指向的方法有哪些吗?(这个面试官也问的很频繁)
call apply bind
14.了解bind的实现原理吗?可以写一下吗?(我没答上来,确实没看bind的源码,面试官叫我回去多了解了解一些函数实现的源码)
15.让我说一下ES6我熟悉的新特性(这个我简历上写了熟悉ES6,我说了一下Promise)
16.手撕:数组扁平化(你们去搜下啦,方法有还几个,我当时没写出来,面试官说让我说下思路就行,我后面下去查才知道原来这题是个高频手撕题)
输入:[1,2,3,4,5,6,[7,8,[9]]] 输出:[1,2,3,4,5,6,7,8,9]
17.反问
没了~
二面:(25min)
就问了几个问题,而且非常含糊其辞的问没有直接问,我差点没反应过来
具体怎么问的我忘记了,考的知识点我列一下
1.http状态码
2.遇到状态码为504我们怎么处理?(不会呜呜呜,面试官人很好给我讲了一下不过我紧张也没记住)
3.知道react吗?(问了个相关问题,我根本没学,只能实话实说不知道)
4.任何关系型组件通信(这个面试官问的比较隐晦,我心里也没底在寻思到底问的是不是这个问题啊,我让面试官又重复跟我描述一下才晓得在问这个,所以大家不懂千万不要乱回答呀,一定要问清楚别怕,知道在问什么再去回答)(vue组件通信问的频率也非常之高!)
5.vue2双向数据绑定原理,还问我了解vue3吗(呜呜不了解)
6.css3有许多新特性,能说一下你用过什么吗?我说了动画
7.就又到了反问
总结:
两个面试官都非常又耐心,会循序渐进的问,不会的也会告诉我去学习,或者逐步指导我,大家秋招继续一起加油!