前言
春天到了,万物复苏,阳和启蛰,品物皆春。身边的小伙伴们也骚动了,出现了一股提桶风,为了实时了解市场,我就问了一些小伙伴今年的面试问题,顺便做下汇总,给正在面试的友友们一些思绪,强行给友友蓝buff加持,面试自然马到功成。其实大多数问题还是老生常谈的在我的上一篇文章基本都囊括在内了。2021年我的前端面试准备
本篇文章会持续更新,完善成为2022大家的前端面试准备
面试必问第一题
第一题当然是自我介绍咯,这也是一门学问,是一场面试的开始,也是面试官对你的初步影响,我认为很重要!所以每次我去面试之前都会反复推敲一些词语。下面我讲几个重点
- 调整最好的精气神,开门见山,大大方方。
- 清晰自我定位,突出自我优势。
- 用词恰当,干练简洁,表达清晰。
举个栗子:面试官你好,我叫伊人a,想面试贵公司的前端工程师岗位,我从业前端X年有余,技术栈主要是Vue、React,同时也做过H5以及小程序。(做过比较牛的项目可以说说,实在没有没必要尬下去。)
这是针对技术面试官,如果是HR或者老板,你得随机应变,因为他们想了解的东西不一样,
面试官的话只想知道你会什么,思考能力。
老板的话只想只要你得价值。
HR的话只想知道你这个人到底咋样。
面试题
1. 圣杯和双飞翼实现方式的区别?
答:共同点:
- 都使用了float
- 中间部分在文档前面,为了优先加载
区别:
- 圣杯:
左、中、右三个盒子在一个同一个盒子中,设置外侧盒子的padding
,从而留出两侧盒子位置
- 双飞翼:
左、中、右三个盒子同级,在中间盒子里放一个小盒子,设置小盒子的margin
,从而留出两侧盒子位置
元素居中的方式
答:
- 使用
margin
进行固定长度的偏移
/*关键样式代码*/
#father{
overflow: hidden;
}
#son{
margin:0 auto;/*水平居中*/
margin-top: 50px;
}
复制代码
- 使用绝对定位并进行偏移
/*关键样式代码*/
#father{
position:relative;
}
#son{
position: absolute;
left:50%;
margin-left: -50px;
top:50%;
margin-top: -50px;
}
/*优化代码(使用css样式中的计算公式)*/
#son{
position: absolute;
left:calc(50% - 50px);
top:calc(50% - 50px);
}
复制代码
- 使用绝对定位并
margin
自适应进行居中
/*关键样式代码*/
#father{
position:relative;
}
#son{
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
margin:auto;
}
复制代码
- 使用
table-cell
进行居中显示
/*关键样式代码*/
#father{
display: table-cell;
vertical-align: middle;
}
#son{
margin: 0 auto;
}
复制代码
- 使用弹性盒子来实现居中
#father{ display: flex; justify-content: center; align-items: center; }
复制代码
3.讲讲闭包以及在项目中的使用场景
闭包可以理解为定义在一个函数内部的函数
它可以实现变量私有化但同时容易造成内存泄漏
使用场景主要有返回值、函数赋值、自执行函数、迭代器等等
4.讲讲promise以及在项目中的使用场景
ECMAscript 6 原生提供了 Promise 对象。
Promise 对象代表了未来将要发生的事件,用来传递异步操作的消息。
Promise 对象有以下两个特点:
1、对象的状态不受外界影响。Promise
对象代表一个异步操作,有三种状态:
pending
: 初始状态,不是成功或失败状态。fulfilled
: 意味着操作成功完成。rejected
: 意味着操作失败。
只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是 Promise 这个名字的由来,它的英语意思就是「承诺」,表示其他手段无法改变。
2、一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise
对象的状态改变,只有两种可能:从 Pending
变为 Resolved
和从 Pending
变为 Rejected
。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,你再对 Promise 对象添加回调函数,也会立即得到这个结果。这与事件(Event
)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
Promise 优缺点
有了 Promise
对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise
对象提供统一的接口,使得控制异步操作更加容易。
Promise
也有一些缺点。首先,无法取消 Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise
内部抛出的错误,不会反应到外部。第三,当处于 Pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
5.谈谈Promise.all方法,Promise.race方法以及使用
-
Promise.all可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。(Promise.all 方法的参数不一定是数组,但是必须具有 iterator 接口,且返回的每个成员都是 Promise 实例。)
-
顾名思义,Promse.race就是赛跑的意思,意思就是说,Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。
Promise.all
可以比作接力跑,必须都成功才能胜利
Promise.race
可以比作短跑,谁跑的快睡就胜利
使用场景
在前端开发请求数据的过程中,偶尔会遇到发送多个请求并根据请求顺序获取和使用数据的场景,使用Promise.all毫无疑问可以解决这个问题。
Promise.race则是在拼手速抢东西就可用到
6.谈谈你理解的vue(这个问题很广可以用react、Angular进行比较说明)
Vue
是个渐进式的轻量框架渐进式代表的含义是:主张最少。
每个框架都不可避免会有自己的一些特点,从而会对使用者有一定的要求,这些要求就是主张,主张有强有弱,它的强势程度会影响在业务开发中的使用方式。
比如说,Angular
,它两个版本都是强主张的,如果你用它,必须接受以下东西:
- 必须使用它的模块机制- 必须使用它的依赖注入
- 必须使用它的特殊形式定义组件(这一点每个视图框架都有,难以避免)
所以Angular是带有比较强的排它性的,如果你的应用不是从头开始,而是要不断考虑是否跟其他东西集成,这些主张会带来一些困扰。
比如React,它也有一定程度的主张,它的主张主要是函数式编程的理念,比如说,你需要知道什么是副作用,什么是纯函数,如何隔离副作用。它的侵入性看似没有Angular那么强,主要因为它是软性侵入。
Vue可能有些方面是不如React
,不如Angular
,但它是渐进的,没有强主张,你可以在原有大系统的上面,把一两个组件改用它实现,当jQuery
用;也可以整个用它全家桶开发,当Angular
用;还可以用它的视图,搭配你自己设计的整个下层用。你可以在底层数据逻辑的地方用OO和设计模式的那套理念,也可以函数式,都可以,它只是个轻量视图而已,只做了自己该做的事,没有做不该做的事,仅此而已。
渐进式的含义,我的理解是:没有多做职责之外的事。
7.关于Vue的组件传值有哪些?
-
子组件props接受父组件传值,向父组件传值时需要使用
vue
中的$on
和$emit
-
eventBus
创建一个Vue的实例,让各个组件共用同一个事件机制。
传递数据方,通过一个事件触发eventBus.emit
( 方 法 名 , 传 递 的 数 据 ) 。 接 收 数 据 方 , 通 过 mounted( )
触 发 eventBus.emit
(方法名,传递的数据)。 接收数据方,通过mounted(){}触发eventBus.emit(方法名,传递的数据)。接收数据方,通过mounted()
触发eventBus.on(方法名,function(接收数据的参数){用该组件的数据接收传递过来的数据})
provide和inject
8.谈谈provide和inject
成对出现:provide和inject
是成对出现的
作用:用于父组件向子孙组件传递数据
使用方法:provide
在父组件中返回要传给下级的数据,inject
在需要使用这个数据的子辈组件或者孙辈等下级组件中注入数据。
使用场景:由于vue
有$parent
属性可以让子组件访问父组件。但孙组件想要访问祖先组件就比较困难。通过provide/inject
可以轻松实现跨级访问父组件的数据
provider/inject
:简单的来说就是在父组件中通过provider
来提供变量,然后在子组件中通过inject
来注入变量
需要注意的是这里不论子组件有多深,只要调用了inject那么就可以注入provider中的数据。而不是局限于只能从当前父组件的prop属性来获取数据。
9.说说Vuex
Vuex
是一个专为 Vue.js
应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
Vuex
可以帮助我们管理共享状态,并附带了更多的概念和框架。这需要对短期和长期效益进行权衡。
如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。确实是如此——如果您的应用够简单,您最好不要使用 Vuex。一个简单的 store 模式就足够您所需了。但是,如果您需要构建一个中大型单页应用,您很可能会考虑如何更好地在组件外部管理状态,Vuex 将会成为自然而然的选择。
store
注入 vue的实例组件的方式,是通过vue
的 mixin
机制,借助vue
组件的生命周期 钩子 beforeCreate 完成的。即 每个vue
组件实例化过程中,会在 beforeCreate
钩子前调用 vuexInit
方法。
10.路由守卫有哪些?
路由守卫又称导航守卫,指是路由跳转前、中、后过程中的一些钩子函数。官方解释是vue-router
提供的导航守卫,要通过跳转或取消的方式来守卫导航。路由守卫分为三种,全局路由、组件内路由,路由独享。
全局路由钩子函数有:beforeEach、beforeResolve、afterEach(参数中没有next)
组件内路由的钩子函数有:beforeRouterEnter、beforeRouteUpdate、beforeRouteLeave
路由独享的钩子函数有:beforeEnter
11.箭头函数与普通函数的区别
-
箭头函数是匿名函数,不能作为构造函数,不能使用new
-
箭头函数不绑定
arguments
,取而代之用rest
参数…解决 -
箭头函数不绑定
this
,会捕获其所在的上下文的this值,作为自己的this值 -
箭头函数通过
call() 或 apply()
方法调用一个函数时,只传入了一个参数,对 this 并没有影响。 -
箭头函数没有原型属性
-
箭头函数不能当做
Generator
函数,不能使用yield
关键字
12.Git常用指令
-
检出仓库:$ git clone
-
查看远程仓库:$ git remote -v
-
添加远程仓库:$ git remote add [name] [url]
-
删除远程仓库:$ git remote rm [name]
-
修改远程仓库:$ git remote set-url –push [name] [newUrl]
-
拉取远程仓库:$ git pull [remoteName] [localBranchName]
-
推送远程仓库:$ git push [remoteName] [localBranchName]
- *如果想把本地的某个分支test提交到远程仓库,并作为远程仓库的master分支,或者作为另外一个名叫test的分支,如下:
$git push origin test:master // 提交本地test分支作为远程的master分支
$git push origin test:test // 提交本地test分支作为远程的test分支
-
查看本地分支:$ git branch
-
查看远程分支:$ git branch -r
-
创建本地分支:$ git branch [name] —-注意新分支创建后不会自动切换为当前分支
-
切换分支:$ git checkout [name]
-
创建新分支并立即切换到新分支:$ git checkout -b [name]
-
删除分支:$ git branch -d [name] —- -d选项只能删除已经参与了合并的分支,对于未有合并的分支是无法删除的。如果想强制删除一个分支,可以使用-D选项
-
合并分支:$ git merge [name] —-将名称为[name]的分支与当前分支合并
-
创建远程分支(本地分支push到远程):$ git push origin [name]
-
删除远程分支: gitpush origin :[name]
13.Git代码回滚
-
git reset –hard HEAD^ 回退到上个版本
-
git reset –hard HEAD~3 回退到前3次提交之前,以此类推,回退到n次提交之前
-
git reset –hard commit_id 退到/进到,指定commit的哈希码(这次提交之前或之后的提交都会回滚)
14.axios怎么去做请求拦截
// 请求拦截器
instance.interceptors.request.use(req=>{}, err=>{});
// 响应拦截器
instance.interceptors.reponse.use(req=>{}, err=>{});
复制代码
- 请求拦截器
// use(两个参数)
axios.interceptors.request.use(req => {
// 在发送请求前要做的事儿
...
return req
}, err => {
// 在请求错误时要做的事儿
...
// 该返回的数据则是axios.catch(err)中接收的数据
return Promise.reject(err)
})
复制代码
- 响应拦截器
// use(两个参数)
axios.interceptors.reponse.use(res => {
// 请求成功对响应数据做处理
...
// 该返回的数据则是axios.then(res)中接收的数据
return res
}, err => {
// 在请求错误时要做的事儿
...
// 该返回的数据则是axios.catch(err)中接收的数据
return Promise.reject(err)
})
复制代码
后续会持续更新此文,建议点赞收藏。
每当我收集到一份面试纪实都会实时更新上来,希望能给友友带去些许帮助。也欢迎友友留言自己遇到的一些面试题目,我会认真看的哦!和友友们一起进步挣大钱是一件很有意义的事情!!!哈哈哈
掘金足迹
2021年06月23日14点26分发布了我的第一篇文章两年前端程序媛从0到18k的逆袭之路 | 2021年中总结
2021年07月27日10点09分发布了我的第二篇文章2021年我的前端面试
2021年12月13日13点55分发布了我的第三篇文章没有伞的程序媛必须努力奔跑|2021年终总结
写在最后
我是伊人a,很高兴认识你。
– 文中如有错误,欢迎在评论区指正,如果这篇文章帮到了你,欢迎点赞和关注?
– 本文首发于掘金,未经许可禁止转载?