0.答题小技巧(前言)
可能很多小伙伴在回答面试题时,都大概知道是个什么东西,但是无法很好的表述出来,那么可以参考一下面试题技巧。
首先应该对面试题进行分类,针对不同的问题给予不同的答案。
常见的面试题类型有概念类,比如 说说你对promise的理解? 这样的题目,就是概念类,我们可以从以下几个方面来回答问题。 (越多越好)
a.xxx是什么? promise是ES6新增的一个构造函数
b.xxx的作用?它主要解决了回调地狱。
c.xxx的工作原理?promise有三种工作状态....(原理省略,可见下方原题)
d.xxx有什么好处?可以简化代码,提高了维护性。
e.是否存在什么问题? 代码仍然存在冗余
f.是否有替代方案? 可以使用async await进行替代 对代码进行进一步简化,完美解决了嵌套问题。
还有流程类,比如 说说new一个构造函数的步骤? 这种就是流程类,我们可以这样回答。
new一个构造函数主要分为4步,第一步是创建一个实例对象,第二步是this会指向这个实例对象,第三步是执行赋值代码,第四步是返回这个对象。
还有一种是区别类。比如说说em和rem的区别?这种有区别两个字是跑不掉的,可以先说以下em和rem是什么,然后再说一下它们共有几个区别,分别是什么什么,我们可以这样回答。
em和rem都是相对单位,但是它们的区别主要是:em是相对于当前元素的字体大小,而rem是相对于html根元素字体大小。
当然,技巧都是死的,人是活的,最终还是应该灵活应对面试官,见招拆招,最好可以学会引导面试官~~
好的,接下来步入正题(自己对于面试题的一些总结)
一 布局结构类
1.【CSS】em和rem的区别是什么?
em和rem都是相对单位,em相对于元素本身的字体大小,而rem是相对于html根元素的字体大小。
2.【CSS】rem适配的原理是什么?
动态检测屏幕的变化,不同屏幕的配置相应的根元素字体大小。当改变屏幕大小的时候,根元素字体大小也会相应改变。那么使用rem作为单位的元素大小也会相应改变,这就是适配的原理。
3.【CSS】如何实现一个盒子水平垂直居中?
(1)使用子绝父相定位+margin
(2)使用子绝父相定位+transform:translate
(3)使用子绝父相定位 然后将四个方向设置为0 然后margin:auto
(4)使用flex布局
4.【CSS】说一下对BFC的理解?
BFC是块级格式化上下文。
主要用于解决了内部包含浮动元素,清除浮动的外部影响,上下外边距的合并,以及外边距的塌陷问题。
常见的BFC情况有:overflow不为visible display为inline-block position为绝对或者固定,html元素,float浮动,还有c3新增的一个display:flow-root,就是专门用来转为BFC格式的。
5.【CSS】说一下link和@import的区别?
首先link和@import他们的作用都是用来引入css样式的,但是@import是一种方式,而link是内部的一个标签。标签除了可以用来引入css样式外还可以用来定义ref等属性。
因此link引入的样式的权重会比@import要高,然后加载的机制也不同,link是随着css样式一起被加载,而@import是等dom渲染完成后再加载。
6.【HTML】说一下H5的新特性?
(1)语义化标签
(2)拖拽释放
(3)新技术 websocket,webworker
(4)本地存储localstorage,sessionstorage (5)自定义属性
(6)视频音频自动播放
(7)画布canvas
(8)表单控件
(9)地理Geolocation API
7.【CSS】实现双飞翼(圣杯)布局?
(1)可以将左右两侧盒子宽高固定,中间使用flex:1
(2)设置一个盒子的左右内边距,然后定位两个盒子到该盒子的左右两侧
8.【CSS】CSS盒子模型?
CSS的盒子主要分为标准盒子模型和怪异盒子模型,标准盒子模型由里面的内容content+padding+border+margin组成,我们所设置的宽度width就等于content的宽度。而怪异盒子模型虽然也是由content+padding+border+margin组成,但是其width是等于content+padding+border三部分组成。
9.【CSS】CSS选择器的优先级?
从大到小 !important>行内样式>id选择器>类选择器>标签选择器>通配符>继承>浏览器默认属性
10.【CSS】CSS中哪些常见的属性可以继承,哪些不可以?
可继承:font字体属性,font-size,font-weight,font-family,font-style。还有颜色color,行高line-height,块级元素text-align,元素的可见性visibilty,还有表格布局属性和列表布局属性也可以继承。
不可继承属性:盒子模型属性,包括width,height,margin,padding,border,背景属性background,定位属性float,position等。
11.【CSS】display:none和visibility:hidden的区别?
首先这两个设置都可以实现元素的隐藏,但是display不会占空间位置,而visibility会占据空间位置,这是最重要的区别,此外visibility拥有继承性,而diplay:none是没有的,还有一点就是visibility因为占位置的特性,只会引起重绘,而display会引起回流。
12.【CSS】position定位的属性有哪一些?
position的定位属性分别是static(默认),absolute(绝对定位),relative(相对定位),fixed(固定定位),sticky(粘性定位),inherit(继承父类的定位属性)。
13.【CSS】如何解决浮动带来的负面影响?
(1)通过设置高度
(2)在浮动的盒子后面增加一个盒子,设置clear:both
(3)单伪元素,双伪元素
(4)设置overflow:hidden
14.【CSS】CSS3的新特性
(1)颜色新增RGBA,HLSA类型
(2)文字阴影,text-shadow
(3)边框圆角border-radius,边框阴影border-shadow
(4)盒子模型 box-sizing
(5)渐变色
(6)过渡transition
(7)动画keyframes和animation
(8)2d/3d转换 transform
(9)flex布局
二 JS类
1.【JS】说一下call和apply和bind的区别?
首先call和apply和bind都是用来改变函数的this的指向的。他们的区别主要有两个:
(1)call和apply是改变函数的this指向并且立即执行函数,而bind是改变函数的this指向然后返回一个新的函数,它起到的作用仅仅只是改变,如果要调用的话,还得调用返回后的新的函数。
(2)call和bind的第一个参数是修改后的this指向,后面的参数是参数列表,而apply第一个参数是修改后的this指向,后面的参数是数组或者是伪数组。
2.【JS】说一下对于事件委托的理解?
事件委托就是利用事件冒泡的原理,将原属于子元素的事件委托给父元素注册。
它的好处主要是可以提高浏览器的效率,优化用户体验。
3.【JS】说一下对于防抖和节流的理解?
防抖就是单位时间内只反复触发某一事件触发最后一次,节流就是单位时间内反复触发某一事件只触发一次。打比方的话,防抖类似于英雄联盟内的回城,节流类似于csgo中的散弹枪。
使用例子:比如用户的输入框,input事件就要用防抖,比如滚动条,就可以用节流。
他们的目的都是优化性能,提高用户的体验感。
想使用的话一般是使用lodash里面的debounce 和throttle或者 尝试自己封装。
4.【JS】说一下对于EventLoop的理解?
EventLoop就是事件循环机制,它是单线程语言js用于运行代码时不被阻塞的一种机制。它的执行机制是先执行同步代码,将异步代码分为微任务和宏任务,分别放入微任务区和宏任务区,执行完所有同步代码之后再执行异步代码,异步代码先执行微任务再执行宏任务。
常见的微任务有 promise.then里面的代码 和 await后面的代码
常见的宏任务有 script标签、定时器、事件处理函数、ajax
5.【JS】如何并发请求并根据请求的书写顺序拿到对应的结果?
可以使用promise.all() 在all中放一个数组,数组中书写请求。 例如promise.all([请求1,请求2,请求3]) 然后可以使用.then 拿到结果,假设这个结果为res,那么res就是存放了三个请求的返回值的数组,这样就可以拿到相对应的结果。
6.【JS】说说对于Promise的理解?
Promise是ES6新增的一个构造函数,它的作用是解决回调地狱。Promise在我看来它相当于是一个容器,里面用来存放异步代码。它有三种工作状态,分别是pending进行中,fulfilled已完成,rejected已失败。
Promise默认是pending状态,因此里面的代码会立即执行,它的状态有两种变化。当调用resolve方法时,会从进行中变成已完成,当调用reject时,会从进行中变成已失败。
当Promise状态发生改变后,相当于结果已经凝固,任何时候都可以获取结果。用promise.then()方法获取成功的结果,用promise.catch()方法获取失败的结果。
替代方案:promise虽可以解决回调地狱,但是代码依然冗余,可以使用async await来解决冗余的问题。
7.【JS】说说函数传参时简单数据类型和复杂数据类型有什么差异?
简单数据类型的值存放在栈空间,如果对简单数据类型进行拷贝赋值,修改拷贝后的数据对原数据没有影响。
复杂数据类型的值存放在堆空间中,如果对复杂数据类型进行拷贝,拷贝的实际上是栈地址,如果修改拷贝后的数据,会对原来的数据造成影响。
而函数的传参,就是实参给形参赋值,相当于是对数据进行拷贝,因此如果在函数内部修改复杂数据类型的话,原数据也会受到影响,而如果在函数内部修改简单数据类型的话,原数据不会受到影响。
8.【JS】说一下图片懒加载的原理?
举一个实际情况的例子,假设一个网页有2000px高,当我们刚进入这个网页时,视口上只会显示800px的内容,剩下的1200px是看不到的。我们可以将下方的图片设置为懒加载,只有当页面向下滚动到一定位置时,图片才会加载,这样可以提高刚开始进入网页的速度,提高性能。
实现方法:给img标签设置一个自定义属性,比如data-img设置图片的路径,然后给页面添加一个scroll事件,当滚动到一定位置时,将图片的src属性设置为data-img,这样就可以实现图片的懒加载了。
9.【JS】说一下null和undefined的区别?
相同点:
null和undefined转换为boolean类型都是false,它们的值相同。(null == undefined)为true
不同点:
null转成数字类型是0,undefined转成数字是NaN,它们的类型不同。(null === undefined)为false
10.【JS】说一下你对闭包的理解?
闭包就是一个使用了外部函数局部变量的函数。我对闭包的理解更像是一种被动技能,一般不会主动去使用,而是有时候用着用着就会产生闭包。它的存在更像是JS世界中的空气,无处不在。
11.【JS】说一下localstorage和sessionstorage和cookie的区别?
它们的区别主要有三点,分别是数据的生命周期,数据大小的限制,和与服务器端通信的方式。
数据生命周期方面: cookie一般由服务器生成,可以设置失效时间,如果不设置失效时间,默认浏览器关闭时失效,如果设置了失效事件,则是到了失效时间后再失效。localstorage存储在硬盘中,长期存储。sessionstorage存储在内存中,当关闭页面或者关闭浏览器时失效。
数据大小方面: cookie一般是4kb,而localstorage和sessionstorage一般是5MB左右。
与服务器端通信方面: cookie会放在http请求头中,发送给服务器,因此使用cookie过多会对性能造成影响。localstorage和sessionsotrage都存在浏览器中,不参与和服务器端的通信。
12.【JS】如何判断一个对象为空?
可以使用JSON.stringify(对象),将对象转换成JSON字符串,再判断字符串是否为空,还可以使用Object.keys(对象),来获取对象键的数组,然后判断数组的长度是否为0。
以上两种方法都存在缺陷(这里就不展开说了),面试官比较希望听到的答案是Reflect.ownKeys(对象),这种方法比较完美,可以获取对象键的数组,然后判断数组长度是否为0即可。
13.【JS】说一下for-in和for-of的区别?
- for-in适合遍历对象属性,for-of适合遍历数组
- for-in循环出的是key值,for-of循环出的是value
- for-in可以遍历可枚举的属性,for-of遍历的是可迭代的
- for-of不能直接遍历普通的对象,需要通过Object.keys()搭配使用
14.【JS】说一下箭头函数和普通函数的区别?
箭头函数和普通函数主要有三个不同点。
1.箭头函数和普通函数的写法不一样
2.箭头函数没有arguments对象
3.最重要的区别:箭头函数没有this指向,在箭头函数中的this会指向上级作用域的this,因为没有this,箭头函数不能进行上下文的调用,也不能作为构造函数使用。
15.【JS】什么是重绘和回流,如何减少?
重绘:当页面中元素样式的改变并不影响它在文档流中的位置时,也就是说布局没有发生改变时(比如只是改变元素的颜色)。
回流:当DOM树中的部分(或全部)元素的尺寸、结构、显示隐藏等发生改变时,浏览器重新渲染的过程称为回流。
回流一定会重绘,但重绘不一定会回流,重绘和回流会对浏览器的性能产生影响,但是回流的影响更大,有时候修改一个子元素的样式,它的的父元素以及任何跟它相关的元素也会产生回流,牵一发动全身。
如何减少:
(1)尽量避免修改style属性,而是去修改元素的class属性,来获取自己想要的效果
(2)尽量减少使用dom操作
(3)如果可以的话,可以先将元素隐藏,把样式设置好之后再让它显示出来
16.【JS】说说你对继承的理解?或者说说什么是组合式继承?
在Js中,继承主要是有三种方式,分别是盗用构造函数继承,原型链继承和组合式继承。盗用构造函数只能继承父类的属性,而无法继承到原型上的方法,原型链继承只能继承原型上的方法,而无法继承属性,将两者结合在一起,形成组合式继承,可以完整的实现继承的功能。但是ES6新增了class和extends,如果我在开发者有用到继承的话,可能会优先考虑到使用extends实现继承。
17.【JS】说说你对原型链的理解?
原型链就是多个对象之间通过__proto__之间进行连接而形成的一种链式的结构,就是原型链。在原型链上遵循就近原则,访问不存在的属性返回undefined,访问不存在的方法会报错。
18.【JS】说一下new一个构造函数的执行过程?
(1)创建一个空的实例对象
(2)然后this指向这个实例对象
(3)执行赋值代码
(4)返回这个对象
三 VUE框架
1.【Vue】v-for和v-if为什么不建议放一行?
因为在vue2中v-for的优先级要比v-if高,因此每执行一次v-for,都会执行一次v-if,会极大的消耗性能,所以不建议放在一行。
但是在vue3中这个问题已经解决了,可以放在一起使用。
2.【Vue】Vue 响应式四连问?
这个问题实际就是面试官 ,分别是vue2中哪些操作不是响应式的?为什么?解决方式?vue3呢?
问题多,但是不要慌张,哈哈,一个个回答即可。
在vue2中,当通过下标去修改数组时,不是响应式;通过delete去删除对象中的某一项时,不是响应式;给对象新增的属性赋值时,不是响应式的。
原因:vue2中当通过下标去修改数组时,不是响应式,尤大当时的原话说是为了性能考虑,但是不知道vue3咋偷偷改好了。当通过delete去删除对象中的某一项时,无法做到响应式,是因为在vue2中实现双向绑定的原理是通过Object.defineProperty去劫持数据的getter和setter,但是其不支持删除操作,无法做到响应式。而给对象新增的属性赋值时,不是响应式是因为这时候数组中还没有该属性,Object.defineProperty自然无法劫持到,无法做到响应式。
解决方式:可以通过$set去强制更新,通过下标修改数组不是响应式可以通过一些可以响应的数组方法去处理,比如splice等。
vue3:采用proxy代替了Object.defineProperty,解决了非响应式的问题。
3.【Vue】hash 和 history 模式的差异是什么?
hash和history是路由模式,但是它们也是也差异的。
(1)它们两者的兼容性是不同的,hash的兼容性比history的兼容性要强,hash可以向下兼容到IE8,history只能向下兼容到IE10,如果说项目对兼容性有特殊要求,可以使用hash模式。
(2)它们的表现形式不同,hash在路由中的表现会带#号,而history不会。
(3)hash不会向后端发起请求,而history会向后端发起请求,要让后端做相应的设置,才能正常访问页面。
使用场景的话,其实还是看公司要求,像某易云音乐官网其实就是使用的hash模式,并非在url中展示#号就一定有啥不好。
4.【Vue】父传子都有哪些方法?
在vue中进行父传子的操作时,主要有这么几种方式。
(1)使用自定义属性,然后子组件通过props接收,如果子组件不用props接收的话,vue会将属性注入,子组件可以通过$attrs获取到属性
(2)使用$children获取子组件实例,但是vue3已经废弃了。
(3)通过ref获取子组件实例
(4)通过vuex进行传值
(5)通过slot插槽传递
5.【Vue】子传父都有哪些方法?
在vue中进行子传父的操作时,主要有这么几种方式。
(1)通过$parent获取父组件实例
(2)通过$emit传值
(3)通过vuex进行传值
(4)作用域插槽传值
6.【Vue】说一下 Vue 中的兄弟组件通信?
vue中兄弟组件通信方式,主要有两种方式。
(1)通过状态提升,将兄弟组件通信转为父子组件通信
(2)vuex
7.【Vue】说一下Vue nextTick?
在vue中,出于性能考虑,每次数据改变,视图并不会立即更新。因此刚修改完数据,便去获取视图的结果,是会有问题的,这时候就可以使用$nextTick,其可以保证等视图更新完毕之后再去执行其中的代码。
8.【Vue】你会在哪个钩子里面发请求为什么?
看情况,如果是对data数据进行操作,我会在created钩子中进行操作,因为这个时候数据获取完毕,是最早可以修改数据的时机。如果要做的操作依赖于dom,那么我会在mounted钩子中操作,因为在mounted钩子中最早挂载完挂载点,可以开始操作dom。
9.【Vue】如何监听组件某个生命周期钩子的触发?
如果是在vue2中,可以通过
@hook:组件某个生命钩子="方法名"去监听组件某个生命周期钩子的触发,如果在vue3中,可以通过@vnode-组件某个生命钩子="方法名"去监听组件某个生命周期钩子的触发。
10.【Vue】说一下 computed 和 methods 及 watch 之间的差异?
(1)首先它们的功能不同,computed是计算属性,methods是方法,而watch是侦听器
(2)computed和methods其实都可以实现计算属性的功能,但是computed有缓存,而methods是没有缓存的,watch也是没有缓存的。
(3)computed是不支持异步操作的,而methods和watch都是支持异步操作的
(4)computed和data平级,必须是data中没有的属性,而watch侦听必须是已经存在的元素。
11.【Vue】v-show 和 v-if 的异同?
v-if的本质是元素的新增和移除,而v-show的本质是修改元素的display属性,因此v-show拥有更高的初始渲染成本,v-if拥有更高的反复渲染成本呢。在使用时需要视情况而定。当某一个组件需要来回切换,多次显示隐藏时,最好使用v-show,反之,如果很少进行操作,则使用v-if。
12.【Vue】说一下 Vue 有哪些内置组件,分别是什么意思?
(1)template 不会被渲染,主要用来配合slot使用
(2)transition 可以做一些动画过渡的操作
(3)keep-alive 可以缓存组件
(4)component 用于动态组件
13.【Vue】Vue 父子组件嵌套的话,生命周期顺序是什么?
口诀的话就是父子子父, 只有前面两个阶段略有不同。
(1)父组件的beforecreate
(2)父组件的created
(3)父组件的beforemount
(4)子组件的beforecreate
(5)子组件的created
(6)子组件的beforemount
(7)子组件的mounted
(8)父组件的mounted
(9)父组件的beforeupdate
(10)子组件的beforeupdate
(11)子组件的updated
(12)父组件的updated
(13)父组件的beforedestory
(14)子组件的beforedestory
(15)子组件的beforedestory
(16)父组件的destoryed
14.【Vue】和 Vue 相关性能优化的手段你了解哪些?
(1)路由懒加载
(2)异步组件
(3)设置key值
(4)合理使用v-if和v-show
(5)合理使用Keep-alive组件
(6)尽量拆分组件,提高复用性
15.【Vue】说一下对于vuex的理解?
vuex是vue2提供的一个全局状态管理库,里面有6个配置项,分别是state,getters,mutations,actions,modules,plugins。
state用来存放普通数据,getters用来存放计算属性,mutations用于修改数据,actions用来存放异步代码,modules用来进行模块管理,plugins用来存放一些插件配置。 vuex的存在主要解决了关联性低的组件之间传值不方便的问题。
16.【Vue】说一下Vue实现任意组件通信?发布订阅者模式?
Vue实现任意组件之间进行通信可以使用EventBus(总线通信),使用
$bus.emit()发布,使用#bus.on()去订阅。
17.【Vue】手撕发布订阅者模式?
小埋一坑。
四 业务类
1.【业务】路由级别的权限你是怎么做的?
实现路由级别的权限,一般是在完成登陆时,要从后端返回的数据中获取当前登录用户所拥有的权限数组,然后可以通过该数组对路由进行一个筛选,然后再通过
router.addRoute()方法添加到路由实例中,就可以实现路由级别的权限。可能也会遇到一些问题,这里以vue-admin-template框架为例子,可能会遇到白屏问题,404 not found的问题,还有侧边栏加载问题以及权限混乱的问题。这里篇幅不够,就不展开说明了,如果有感兴趣的小伙伴可以私聊我进行交流。
2.【业务】按钮级别的权限如何实现?
可以通过mixin混入,或者是使用自定义指令的方式,都可以实现按钮级别的权限。 这里说说自定义指令如何实现,前提是登录时的按钮权限还是由后端返回的一个数组展示。比如我有一个删除按钮,只有拥有del权限的人才能删除,在使用自定义指令时,我会往指令中传值,比如删除按钮我就会传del,如果这时后端返回的数组中包含del,那么说明当前用户拥有删除权限,可以显示按钮,反之没有,则隐藏按钮,按钮的显示与隐藏可以通过v-if实现。
3.【业务】小程序的支付如何实现?
首先是看后端接口需要哪些数据,比如商品的数量,价格等信息,然后通过wx.request()将请求发送给后端,后端响应成功会返回一个订单编号,我们可以再将这个订单编号发送给后端,后端会给我们返回一个订单预支付对象,我们再去调用
wx.requestPayment(),将预支付对象发送到微信后台,然后再去请求后端数据,查看对应订单的支付状态,再去做对应的处理。
4.【业务】小程序的登录流程?
首先会调用
wx.login()去获取一个临时的code凭证,然后通过wx.request()将code发送到后端,后端会进行code2session的校验,将appid,appscret,code发送给微信后台,微信的后台会返回给后端一个openid,这个是用户登录的唯一凭证,然后在后端生成token之后,会将token和openid之间进行绑定,做到一一对应。然后会将token返回给前端,前端拿到token之后再去做对应的操作。
5.【业务】SPA和MPA你了解吗?
SPA是单页面,MPA是多页面,像我们常用的vue框架就是单页面开发。单页面开发的主要优势体现在页面跳转速度快,但是首屏加载速度稍慢,并且不利于SEO搜索。多页面开发的主要优势是首屏加载速度快,利于SEO搜索,但是页面跳转速度慢,影响用户体验。
6.【业务】说说如何实现文件上传?
实现文件上传,主要是设置input标签的type设置为file类型,因为样式问题,我在开发中一般会将这个input框隐藏,一般可以设置一个button按钮,然后给这个button按钮设置点击事件,点击button的时候再触发这个input框的点击事件,然后监听input框的change事件,监听到文件上传之后,获取目标文件,再去创建一个formData对象,通过append添加,最后再发送请求上传。
7.【业务】说说如何实现文件预览?
(1)实现文件预览可以通过FileReader的readAsDataURL()的方法,监听change事件,创建一个FileReader的对象,使用对象.readAsDataURL去读取文件内容,然后给对象设置onload事件,等加载完毕给图片的src赋值为对象的result即可。
(2)还可以使用URL.creatObjectURL()实现文件预览,监听change事件,通过URL.createObjectURL(e.target.files[0])去获取一个临时路径,然后给图片的src赋值即可。
8.【业务】说说如何实现excel表格的导入导出?
(1)excel的导入: 实现excel的导入其实类似于文件上传,步骤几乎一样,参考第6题即可
(2)excel的导出: 这里首先得看后端返回的数据是不是blob二进制类型,如果是二进制类型,得在接口处设置一个responseType为blob,表明接受类型为blob,如果是普通数据,我们可以借助xlsx这个包转成二进制。
五 微信小程序
1.说说微信小程序的生命周期?
微信小程序的生命周期分为应用级,页面级,组件级。
应用级常用生命周期:
(1)onLaunch()进入小程序时触发一次
(2)onShow()小程序进入前台时触发一次
(3)onHide()小程序切换到后台时触发一次
页面级:
(1)onLoad() 页面加载
(2)onShow() 页面显示
(3)onReady() 页面初次渲染完毕
(4)onHide() 页面隐藏
(5)onUnload() 页面卸载
组件级: 小程序推荐写在lifetimes中
(1)created() 页面加载
(2)attached() 页面显示
(3)ready() 页面初次渲染完成
(4)moved() 页面隐藏
(5)detached() 页面卸载
(6)error() 抛出错误时触发