一.自我介绍
(我是谁 来自哪里,今天来的目的,面试的岗位是什么,几年的工作经验,掌握的技术栈有哪些,开发过什么项目,项目中负责的板块是什么)
面试官您好!我叫XXX,来自XXX,很荣幸能来我们公司面试,我从事前端开发有3年了,目前掌握的技术有html,css,js,ajax,vue,小程序,参与过各种类型的项目。
我做过的项目有 A,B,C,D,E 那么最近做的一个项目是XXX 在这个项目中我主要负责的板块是XXX 面试官 您这边还有什么想要了解的么。
二.项目功能提问
vue后台项目(这几个功能点要求都能用自己的话说出来)
1.路由守卫 / 导航守卫
既然是守卫,首先是对咱们后台页面访问的一层保护,如果我没有进行登陆过,后台的操作页面是不允许用户访问的
我们是用到vue路由中的一个钩子函数beforeEach,那么这个函数中有三个参数,分别是to from next
to是去哪里 from是从哪里来 next下一步说通俗点就是放行
主要逻辑是判断我们有没有登录,那么我们可以通过登录后获取到的token来判断 如果有token就直接next()放行
如果没有的前提下,我们再判断用户访问的页面是不是登陆页面吗,是的话就放行 不是就跳回登录页
token失效期,我们前端该如何处理。
2.权限路由/动态路由/鉴权
既然说到权限 那么肯定是根据不同账户得到不同的权限来做路由配置和菜单的渲染
第一点当我们登录之后会获取到当前账户的身份(权限),那么我们的路由配置实际上就是一个数组
我们要做的事情就是把获取到的身份与这个数组做对比,通过相关的计算筛选出最终匹配当前身份的路由配置
然后将计算出来的路由数组通过router.addRouters动态挂载
还要注意的一点就是需要将我们筛选出来的路由配置渲染到我们的前端页面上去一一相对应
3.拦截器:请求拦截 响应拦截
请求拦截:因为http是无状态的 无法保存我们的状态,那么我们就需要一个标识
当我们登录之后,后续的所有请求操作都需要携带我们这个token,所以我们统一把它添加到请求头当中,避免了
无意义请求
响应拦截:当设置了响应拦截后所有的响应都会经过它,所以方便我们统一处理响应数据做相关的操作
4.增 删 改 查(增加数据项)
这些操作都是针对与数据来进行操作
增:我们要增加一条数据或者多条数据,首先第一点我们需要获取到增加的数据,然后通过后台提供的相关接口,把数据作为参数传递,当后台拿到我的数据后往数据库中追加这些数据,然后将最新的数据响应给我们,之后再进行渲染
删:首先获取到要删除的这条数据唯一标识可能是ID 可能是code,然后通过后台提供的相关接口,把这个标识作为参数传递,当后台拿到后就会删除这个标识相对应的数据,然后将最新的数据响应给我们,之后再进行渲染
改:首先获取到要修改的这条数据唯一标识可能是ID 可能是code,然后前端进行数据改动,然后通过后台提供的相关接口,把数据作为参数传递,当后台拿到我的数据后往数据库中修改这个标识相对应的数据,然后将修改后的数据响应给我们,之后再进行渲染
查:不要参数, 不需要传递任何参数,直接调用接口获取所有数据
需要参数,首先第一点我们需要获取到需要查询的关键字然后通过后台提供的相关接口,把这些关键字作为参数传递,当后台拿到这个关键字把相对应的数据响应给我们,之后再进行渲染
5.axios的封装
为了方便使用我们进行了封装
首先我们封装一个get或者post的这些方法,然后通过返回一个promise对象进行使用
在promise中通过.then和.catch拿到axios请求结果
然后通过工具层将不同的业务版块需要调用的接口进行模块化再暴露出去
在我们的但页面中引入相对于的接口模块,然后调用,因为我们底层封装的是一个promise对象
所以我们可以通过ES7中的 async await直接拿到响应数据
三.移动端项目功能点(老师自行提问考察2-3个点)
四.小程序功能点(考察2-3个点)
五知识点提问:
1.vue常用指令有哪些?
v-for /v-bind(😃 /v-if/ v-show/ v-else-if /v-else/ v-model / v-on(@) / v-text / v-html / v-once /
v-prev / v-cloak
2.computed和watch的区别是什么?
computed 一对多, 多次调用时,会把第一次调用的结果放入缓存,节约性能
定义的函数必须要写 return,不然会报错
调用的时候不能加括号,不然会报错
在computed中定义一个函数(看起来是一个函数,其实是一个属性)
watch 多对一 只监听,不会产生新的函数名,watch也可以渲染数据,但是和computed比较就比较复杂
3.v-if 和 v-show的区别是什么? 什么时候使用v-if更好? 什么时候用v-show更好?
v-show 可以操作display属性.主要用于频繁操作
v-if 销毁和创建元素,主要是用于大量数据渲染到页面时使用符合条件就将数据渲染,频繁使用会消耗性能
4.数组常用方法有哪些?
pop/ push/ shirf/ unshirf/ reverse/ sort/ splice
find/ findIndexOf/ indexOf / every / some / forEach / map / includes / join / concat / filter / flat /slice
5.new操作具体干了什么?
- 在堆空间中创建一个对象
- this指向这个对象
- 执行构造函数的语句
- 返回这个对象
6.请以自己理解讲解js堆和栈,以及深拷贝怎么解决?(重点)
堆是用来存放引用数据类型,例如对象,数组,函数
栈是用来存放基本数据类型,变量和引用数据类型的地址值 ; 体积小,数据经常变化
深拷贝的解决方案 :
- 使用lodash 插件
- 使用递归解决深拷贝
- 如果数据中没有函数,undefined 可以使用json.stringify+json.parse实现深拷贝
7.跨域引起的原因,以及开发时的解决方案?
跨域: 非同源策略的就叫跨域
同源策略就是相同的http,相同的地址,相同的端口
解决方法: 1 nginx反向代理
8.vue的3种组件通信方式?(重点)
1 父子通信
在嵌套组件中,父组件中的[子组件标签] 绑定自定义属性;
在子组件中 props: { 子组件标签自定义的属性名: { type: , default} }
2 子父通信
在嵌套组件中,父组件中的[子组件标签] ,自定义事件@fn=“”,
在子组件中,触发这个自定义事件
.
e
m
i
t
(
′
自定义的事件
名
′
,
数据
)
/
/
标签中的写法
t
h
i
s
.
.emit('自定义的事件名',数据) //标签中的写法 this.
.emit(′自定义的事件名′,数据)//标签中的写法this.emit() // js中的写法
在父组件的方法中 形参接收数据
3 非父子通信(兄弟通信)
$eventBus
9.vue中key的唯一性的作用,以及异步加载组件的方式?
key的唯一性可以给每一个节点有一个唯一标识,当添加或删除节点时,通过对比数据前后的变化,只用操作某个变化的节点,不需要重新渲染所有的数据,提高了性能
异步加载组件: () => import(‘…/…/’)
10.bfc区域的理解?
Block Formatting context 块级格式化上下文
成立条件有: display:inline-block 或者 position:absolute/ fixed
常用于margin穿透,高度塌陷
11.es6的新增特性
箭头函数,对象属性的简写,解构赋值,模板字符串,类(类的继承),扩展运算符,模块化(moudle),promise,Async / Await (ES7),let const 块级作用域
12.事件冒泡/捕获,以及事件委托。(重要)
捕获: 从document开始,层层子元素传递,直到点击到当前子元素
冒泡: 从点击当前子元素开始,层层父级传递,直到document
事件委托: 将子元素的事件交给父元素处理(主要是添加新的节点,是无法绑定事件,这个时候需要事件委派)
给父元素绑定事件,通过捕获的过程来获取事件,并通过etarget来获取目标元素
13.cookie/localstorage/session区别(重要)
localstorage 本地存储,只有手动删除才会销毁
session数据保存在服务器端,生命周期由服务器端决定
cookie数据保存在客户端 只有4k左右
session和cookie 都是用来跟踪浏览器用户身份的会话方式
14.$nextTick用过吗,有什么作用?
视图更新之后,基于新的视图进行操作
一般created的时候dom没有渲染,如果要操作dom,最好放在this.$nextTick(()=>{})回调函数 中完成
15.vue-router路由的传参方式(重要)
第一种:使用router的name属性也就是params来传递参数
传值页面:
this.
r
o
u
t
e
r
.
p
u
s
h
(
n
a
m
e
:
"
路由配置中对应的
n
a
m
e
名
"
,
p
a
r
a
m
s
:
参数
)
取值页面
t
h
i
s
.
router.push({name:"路由配置中对应的name名",params:{参数}}) 取值页面 this.
router.push(name:"路由配置中对应的name名",params:参数)取值页面this.route.params.userId
第二种:使用query来传递参数
传值页面
this.
r
o
u
t
e
r
.
p
u
s
h
(
p
a
t
h
:
"
/
l
o
g
i
n
"
,
q
u
e
r
y
:
参数
)
取值页面
t
h
i
s
.
router.push({path:"/login",query:{参数}}) 取值页面 this.
router.push(path:"/login",query:参数)取值页面this.route.query.userId
第三种:使用vue里的标签来传递参数
传值页面
Hi页面1
取值页面
this.$route.params.userId
第四种 : 动态路由传参
this.
r
o
u
t
e
r
.
p
u
s
h
(
′
.
/
.
/
′
+
i
d
)
取值页面
t
h
i
s
.
router.push('././' + id) 取值页面 this.
router.push(′././′+id)取值页面this.route.params.id
16.函数的防抖和节流。(重要)
防抖的作用是:当用户多次触发回调函数时,只触发最后一次操作的,其余的全部忽略掉;
函数节流:是确保函数特定的时间内至多执行一次
17.讲解下浏览器的重绘和回流(重要)
回流 (Reflow):当Render Tree中部分或全部元素的尺寸、结构、或某些属性发生改变时,浏览器重新渲染部 分或全部文档的过程称为回流。
会导致回流的操作:
页面首次渲染
浏览器窗口大小发生改变
元素尺寸或位置发生改变
元素内容变化(文字数量或 图片大小等等)
元素字体大小变化
添加或者删除可见的DOM元素
激活CSS伪类(例 如::hover)
查询某些属性或调用某些方法
重绘 (Repaint)
当页面中元素样式的改变并不影响它在文档流中的位置时(例如:color、background-color、visibility等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称 为重绘。
回流一定会导致重绘,重绘不一定会回流
18.js的内存泄露,以及vue中常注意的两种(重要)
- 闭包
ie9之前采用的引用计数算法 - 意外的全局变量
19.请求怎么带token?(放入了哪里?每次请求前做了什么操作) (重要)
1, 获取本地存储中的 token,并放在请求拦截器中,这样所有的请求都可以直接通过请求拦截器将token传给服务器
20.git拿到项目地址时,到修改提交做的流程。
1 git clone 地址
2 git checkout -b 分支名
3 git add .
4 git commit -m"备注"
5 git checkout master
6 git merge 分支名
7 git push origin master
首先需要通过克隆项目地址,将项目拉取到本地仓库,创建新的分支,在分支上编写代码,写完功能后,提交并保存到本地仓库.合并分支后推送到远程仓库
21.post和get的区别?
- get 的参数会显示在地址栏,不安全. 可传的数据量小
- post传的参数不会在地址栏显示,相对安全,可传的数据量大
22.element表格中,如果点击拿当前行的数据怎么写?
使用插槽的格式 v-slot={row} 就可以获取到当前行的数据
23.思考如果要修改上传完头像后怎么,去同步通知头部的头像更新,用到组件的哪个?
修改头像后,在header组件 created钩子中发送请求获取用户信息,
24.promise和async/await区别,简洁讲述? (重要)
- promise是ES6,async/await是ES7
- async/await相对于promise来讲,写法更加优雅
- reject状态:
1)promise错误可以通过catch来捕捉,建议尾部捕获错误,2)async/await既可以用.then又可以用try-catch捕捉
25.get和post的区别 (重要)
- GET在浏览器回退时是无害的,而POST会再次提交请求
- GET请求会被浏览器主动cache,而POST不会,除非手动设置
- GET请求只能进行url编码,而POST支持多种编码方式
- GET请求参数会被完整保留在浏览器历史记录里,而POST的参数不会保留
- GET请求在URL中传送的参数有长度限制,而POST没有
- GET比POST更不安全,因为参数直接暴露在URl上,不能用来传递敏感信息.
- GET参数通过URl传递,POST参数放在Request body中
- 对于参数的数据类型,GET只接受ASCII字符,而POST没有限制
- GET和POST本质上就是TCP链接,并无差别。但是由于HTTP的规定和浏览器/服务器的限制,导致他们在应用过程中体现出一些不同。
26.vue项目中你做的优化?(重要)
小到代码:html的结构/css的样式/js处理数据时候es6的新特性/生命周期销毁优化
大到项目结构:模块改造/组件抽取
vue本身:v-if和v-for的使用/build打包时/sprite精灵图
27.mvvm和mvc区别?它和其它框架jquery的区别
视图结构的概念区别,一个数据驱动一个事件操作,比如后者多为查找dom结构进行操作,前者为渲染时就绑定了methods方法,不用查找
28.vue页面之间的传参(重要)
query 地址栏显示,刷新不丢失,类似get
params 地址栏不显示,隐藏传参,刷新丢失类似post
/:id 动态传参,刷新不丢失同query
29.ES6 Promise 用法,以及使用场景?
等待接口完成,进行下一步操作用promise
配合async和await进行,请求数据回的结构,又或者等待完成进行操作
30.说说你们公司产品开发流程或web前端的开发流程?
产品确定迭代需求/设计进行设计稿设计/小组会议讨论实现可行性,以及后端前端发表意见/前端写页面,后端开发接口/调试接口/自测完成给测试人员测试/上线
31.vue的生命周期是什么?
beforeCreate :创建vue实例 data computed watch methods不能访问;
created: 可以对data数据进行操作, 可进行一些请求,但不易过多,避免白屏时间太长
beforeMount:判断是否有template进行渲染保存到内存当中,但还未挂载在页面上;
mounted: 将内存中的模块挂载到页面上 ,此时可以操作页面上的DOM节点,但还未挂载在页面上
beforeUpdate: 页面显示的数据是旧的,此时data里的数据是最新,页面数据和data数据还没同步;
updated : 根据data里的最新数据渲染出最新的DOM树 然后挂载到页面
beforeDestroy:此时组件从运行进入到销毁阶段 data和methods可用 销毁还未执行;
destroyed : 组件已经完全销毁,所有的方法指令等都不可使用
32.插槽的作用以及使用方式?
组件化时候,有时需要让内容显示到指定位置,用slot的写法,展示出默认内容或自定义内容。
或者具名和匿名插槽的方式用法,具名可以指定位置
33.vue的单项数据流?
答:数据从父级组件传递给子组件,子组件内部不能直接修改从父级传递过来的数据。这样防止子组件意外改变父组件的状态
34.vue中有没有用过组件通信方式 (必背)
父传子:父组件中,子组件上通过属性绑定的方式向子中传递,子中用props接收即可
子传父:通过
e
m
i
t
其中有两个参数第一个作为父中的事件函数
,
第二个是要传递的数据
,
父中在触发函数的形参中拿到乱传
/
兄弟传
:
在
m
a
i
n
.
j
s
中先给
v
u
e
原型上挂载一个
v
u
e
实例
,
在组建中用
emit 其中有两个参数 第一个作为父中的事件函数,第二个是要传递的数据,父中在触发函数的形参中拿到 乱传/兄弟传:在main.js中先给vue原型上挂载一个vue实例,在组建中用
emit其中有两个参数第一个作为父中的事件函数,第二个是要传递的数据,父中在触发函数的形参中拿到乱传/兄弟传:在main.js中先给vue原型上挂载一个vue实例,在组建中用emit来通知
o
n
来监听到
on来监听到
on来监听到emit的通知即可
35.v-on可以监听多个方法么? 要注意什么?(必背)
可以,
1.当没有参数传递时,方法名称后面可以不加小括号
2.当需要传递参数时,且只有一个参数需要传递,而没有进行传递,会默认输出浏览器的event对象
3.当需要传递多个参数时,想要获取浏览器的event对象,需要在前面加$符号
36.vue中ref的作用是什么?(必背)
作用一(基本用法):本页面获取dom元素
作用二:获取子组件中的data
作用三:调用子组件中的方法
作用四:子组件调用父组件方法
37.ES6的新特性有哪些?(必背)
列举常用的ES6特性:
- let、const
- 箭头函数
- 类的支持
- 字符串模块
- symbols
- Promises
- 数据解构
- 展开运算符
38.什么是事件委托?(必背)
让利用事件冒泡的原理,让自己的所触发的事件,让他的父元素代替执行!
39.$route 和 $router 的区别?(必背)
router为VueRouter的实例,相当于一个全局的路由器对象,里面含有很多属性和子对象,
例如history对象,经常用的跳转链接就可以用this.$router.push,和router-link跳转一样。。。
route是一个跳转的路由对象,每一个路由都会有一个route对象,是一个局部的对象,可以获取对应的name,path,params,query等
40…什么是原型链?(必背)
答:实例对象会先查找自身有没有所需成员,如果没有就会通过proto向构造函数的prototype中查找
如果还是没有,又会通过构造函数的prototype的proto去找到object的prototype,还是没有找到
就会通过object的prototype的proto找到null 像这样用proto一层层往上查找的方式,称为原型链
41.什么是递归?(必背)
答: 函数内部自己调用自己, 这个函数就是递归函数 作用和循环效果一样,但很容易发生“栈溢出”错误,必须加退出条件return。
42.什么是闭包?(必背)
答: 函数嵌套函数,函数内部可以访问外部变量,外部不能直接访问该变量闭包保存了自己的私有变量,通过提供的接口给外部使用 延申了作用范围
43.改变this 指向的方式(必背)
答: call()方法调用一个对象。简单理解为调用函数的方式,但是它可以改变函数的 this 指向 应用场景: 经常做继承.
apply() 方法调用一个函数。简单理解为调用函数的方式,但是它可以改变函数的 this 指向。应用场景: 经常跟数组有关系
bind() 方法不会调用函数,但是能改变函数内部this 指向,返回的是原函数改变this之后产生的新函数 应用场景:不调用函数,但是还想改变this指向
如果只是想改变 this 指向,并且不想调用这个函数的时候,可以使用bind
44.JavaScript 有几种类型(必背)
基本数据类型:undefined、null、boolean、number、string、symbol(es6的新数据类型)
引用数据类型:object、array、function(统称为object)
45.组件中 data 为什么是一个函数?
组件上的data是函数的情况下,组件每次调用data里面的数据,都是由data这个独有的函数返回过来的数据,
所以不会造成这个组件更改data的数据,另一个在使用这个数据的组件也会更改这个数据
46.new操作符具体干了什么呢?(必背)
- 创建一个空对象
- this指向这个对象
- 给这个对象添加属性和方法
- 返回这个对象
47.什么是同源(必背)
答: 同源就是两个页面有相同的协议 域名 端口 就属于同源 其中只要一个不同就不同源
48.promise如何使用 有什么作用(必背)
promise是es6中新增的一个构造函数,是为了解决异步操作中数据调用嵌套(回调地狱)的问题。
promise对象提供两个方法 resolve 和 reject 那么需要拿到他们的结果 就需要用到promis对象下的then和carch
49.JS作用域和变量提升?(必背)
作用域:变量起作用的范围 变量访问会层层往上级作用域访问直到window,称为作用域链
变量提升:JS编译阶段会将文件中所有var,function声明的变量提升到当前作用域最顶端
50.为什么构造函数的方法要放在prototype里边为什么不直接用this.的方式声明?(必背)
答:因为prototype占用一个存储空间,实例通过proto指针指向prototype,可以减少内存占用减少不必要的开销
51.函数的防抖和节流。(必背)
防抖函数:将多次触发变成最后一次触发
节流函数:将多次执行变成每隔一个时间节点去执行的函数