总结vue2基础面试

1. 生命周期
1.1 生命周期有哪些?
1.beforeCreate: 初始化实例,this指向创建的实例,不能访问到data、computed、watch、methods上的方法和数据
2.created:实例创建完成,可以访问到data、methods、computed、watch上的数据和方法,未挂载到DOM,不能访问$el属性
3.beforeMount:挂载前被调用,将template编译成render函数
4.mounted:实例挂载到DOM上,可以获取到DOM节点,$ref属性可以访问
5.beforeUpdate:更新之前访问现有的DOM
6.updated:组件数据更新之后
7.beforeDestory:组件实例销毁之前,this仍然可以获取到实例
8.destoryed: 组件实例销毁之后,(关闭页面,播放视频用于记录播放时间 会使用)
// 使用keep-alive额外多出2个生命周期
9.activated: keep-alive缓存的组件激活,(判断id是否相同,不相同就发起请求)
10.deactivated: keep-alive缓存的组件停止调用
1.2发送请求在created还是mounted?
如果渲染页面包含父子组件,并且要去子组件数据优先加载,那么父组件中的请求方法要放在mounted中。如果没有父子组件那么在created和mounted都可以。
1.2 为什么发送请求不在beforeCreate里?

请求封装在methods中时,beforeCreate 阶段拿不到methods中的方法

1.2 进入组件会执行哪些生命周期?

beforeCreate、created、beforeMount、mounted

1.3 父组件引入子组件生命周期执行顺序?
父组件:beforeCreate-->created-->beforeMount-->
子组件:beforeCreate-->created-->beforeMount-->mounted-->
父组件:mounted
1.4在created中如何获取DOM?
因为created中并未挂载DOM,直接输出是拿不到的,需要在异步请求中获取.
<div ref="child"></div> this.$refs.child   获取到dom
1.只要写异步代码就可以获取dom。例如:setTimeout、请求、Promise.xxx()等等
2.使用vue系统内置的this.$nextTick(()=>{})
1.5 加入keep-alive会执行哪些生命周期?

beforeCreate、created、beforeMount、mounted、activated

加入keep-alive,再次进入页面会执行:activated

没有加入keep-alive:beforeCreate、created、beforeMount、mounted

2. 组件
2.1 组件传值方式
父组件传递给后代
1. 父组件传(v-bind)给子组件接收(props):这种父子传递方便,但是父孙比较麻烦,需要父(v-bind)=>(props,v-bind)=>(props);
	子组件不能修改父组件数据,光看不能动
2. 子组件直接使用父组件:this.$parent.xxx;
	子组件可以直接修改父组件数据
3. 父组件直接传递给孙组件:依赖(provide)注入(inject)
	不方便查找数据来源
后代传递给父组件
1. 子组件传值给父组件:this.$emit('change',value)
2. 父组件直接使用子组件:this.$children[0].xxx; 会把子组件使用个数按数组顺序从0开始排布
3. 父组件直接使用子组件:this.$refs.child.xxx;<Child ref="child"></Child>
兄弟之间传值
1. $emit,$on,全局事件总线,谁的数据需要传递,谁就要触发事件
Vue.prototype.$bus = new Vue()
兄弟A触发事件传递:this.$bus.$emit('change',this.value)
兄弟B直接接收:this.$bus.$on('change',value=>{console.log(value)})
2.2 keep-alive

缓存当前组件,重新进入页面无需再次请求数据。

2.3 slot
  1. 匿名插槽:直接用,无法区别
  2. 具名插槽:区别
  3. 作用域插槽:传值
2.4 封装组件
//组件涉及知识点:slot、组件通信...




3. vuex
3.1 vuex有哪些属性
state:全局共享属性
getters:针对state数据进行二次计算
mutations:存放同步方法
actions:存放异步方法,并且是通过提交mutations
modules:把vuex进行模块划分
3.2 vuex使用state值
1. this.$store.state.xxx	可以直接修改vuex的值,既可以使用也可以修改 	模板使用{{$store.state.xxx}}
2. 辅助函数:mapState	中间会拷贝一次vuex数据,不能直接修改,只读
...mapGetters(['name','nickname'])
3.3 vuex使用getters值
1. this.$store.getters.xxx 	两者均不可以赋值修改
2. 辅助函数:mapGetters 	两者均不可以赋值修改
通过输入框v-model去绑定getters值,输入值发生变化是会报错的
3.4 vuex使用mutations值
3.5 vuex使用actions值

3.6 vuex使用modules
1. this.$store.state.user.token
2. 辅助函数 mapState:...mapState({token: state => state.user.token})
3. ...mapActions({findAllByCallId: 'base/findAllByCallId',getSiteCode: 'user/getSiteCode',}),
3.7 vuex持久化存储
  1. vuex本身不具备本地存储,修改vuex中数据后,刷新页面数据会恢复到定义值
  2. 发起请求获取token,将token本地化存储 localStorage.setItem('token',token),然后在vuex中的state去优先读取 localStorage.getItem('token') 本地存储的token,再退出登录时,移除本地存储 localStorage.removeItem('toekn')销毁本地存储
4. 路由
4.1 路由的模式和区别
路由模式:history、hash
区别:
1. 当前页面找不到,history会给后端发送一次请求,而hash不会发送(遇到不存在的乱输网址,history会发送一次请求给后端压力,hash则不会)
2. 表象不同:hash有#,而history有/
3. 项目打包后,前端自测问题:hash是可以看到内容的,而history默认看不到内容需要自己配置项
4.2 子路由和动态路由
4.3 路由传值
4.4 导航故障
import VueRouter from 'vue-router'
const routerPush = VueRouter.prototype.push
VueRouter.prototype.push = function(location){
    return routerPush.call(this, location).catch(err => err)
}
4.5 r o u t e r 和 router和 routerroute区别
$router不仅包含当前路由,还包含整个路由的属性和方法
$route包含当前路由对象
4.6 导航守卫
1. 全局守卫:beforeEach 路由进入之前;afterEach路由进入之后
2. 路由独享守卫:beforeEnter 路由进入之前,对进入该路由做一些限制	(推荐)
{
    path: '/about',name:'about',beforeEnter:function(to, from,next){
        if(true){next()}else{next('/login')}
    }
}
3. 组件内守卫:beforeRouteEnter 路由进入之前;beforeRouteUpdate 路由更新之前;beforeRouteLeave 路由离开之前;(不推荐)
5. API
5.1. $set

this.$set(target,key,修改后的值);target:对象或者数组 key:对象的key或数组的下标 目标值

5.2 $nextTick
获取更新后的DOM,可以异步的去执行函数,解决一些问题;比如:在created生命周期中获取dom元素,可以使用nextTick异步获取
源码|原理
$nextTick(callback){
	return Promise.resolve().then(() => {
		callback()
	})
}
5.3 $refs
用来获取dom元素,方便操作节点
5.4 $data

用来获取当前组件data数据

5.5 $children

获取当前组件的所有子组件

5.6 $parent

找到当前组件的父组件,找不到返回自身

5.7 $root

​ 找到根组件

5.8 $el

获取当前组件的根节点

5.9 data定义数据
数据定义在return内和外的区别:
1. return外:单独修改这个数据是不可以的,没有被object.definePrototype数据劫持
2. return内:正常数据,可以被修改
5.10 computed计算属性

computed计算属性的结果值,可以被修改吗? 可以,需要通过get/set写法

computed:{
    changeNum(){
        return this.num+=10
    },
	changeStr(){
		get(){return this.str.slice(-1)},
         set(value){this.str = value}
	}
}
5.11 watch 监听属性
watch:{
    str(newVal,oldVal){
        console.log(newVal,oldVal)
    },
    obj:{
        handle(newVal,oldVal){
            console.log('obj',newVal,oldVal)
        },
        immediate: true,	// 开启首次监听
        deep:true	// 开启深度监听
    }
}
5.12 methods和computed区别
computed:有缓存机制,重复调用只执行一次
methods:没有缓存机制,重复调用几次执行几次
6. 指令
6.1 v-if和v-for优先级

v-for是大于v-if vue3中 v-if大于v-for

7. 原理
7.1 $nextTick原理

获取更新后的dom。nextTick返回一个promise,让参数callback在 .then异步行为中去执行

7.2 双向绑定原理

通过Object.defineProperty 劫持数据发生的改变,如果数据发生改变(在set中进行赋值),触发update方法进行更新节点内容{{str}},从而实现数据双向绑定的原理

8. axios 二次封装
9. diff算法

提升性能; 把dom结构数据化,不去操作dom结构,而是操作数据,再把数据展示到dom

虚拟dom是表示真实dom的js对象

9.1 新老节点替换
1. 如果新老节点不是同一个节点名称(比如:同div),那么久暴力删除旧的节点,创建插入新的节点
2. 只能同级比较,不能跨层比较,跨层比较会暴力删除新建
 注意:如果要性能提升,一定要加入key,key是唯一的标识,在更改前后,确认是不是同一个节点。
diff算法:
1. 采用分层求异的方式,只对比同层级节点,不会跨层级比较,来查找最小变化,目的是尽可能复用老的节点。
2. 在更新时会生成新的虚拟dom,这时候新旧虚拟dom会进行比较,差别化更新。
比较策略为以下:
2.1.如果新旧节点不一样,直接创建一个新标签替换老标签。
2.2.新旧节点一样,文本不一样,新文本替换旧文本。
2.3.新旧节点一样,新的有子节点,旧的没有子节点,直接添加新的子节点。
2.4.新旧节点一样,新的没有子节点,旧的有子节点,直接删除旧的子节点。
2.5.新旧节点一样,而且都有子节点,那么就要比较子节点:
	内部会采用首尾指针法进行比较,先比对头,头如果不一样,会进行尾尾比较,如果尾不一样,会进行老头跟新尾比较,如果还不一样,会进行老尾跟新头比较。如果都不一样那么会进行乱序比较
    注意:比较这些时候会先判断标签是否一样,再判断key是否一样,判断key的好处在于最大化复用老节点。
10. 项目介绍
10.1 项目上线了吗?
10.2 项目中的token是怎么处理的?
1. 去登录完成之后,一般把密码加密一下,服务端返回给我们一个token,前端做一个密码加密,不加密的话服务端拿到的是一个明文,存在风险,加密的方式一般通过MD5直接进行加密,MD5理论上是不可逆的,
2. 拿到token之后做持久化的登录,本地缓存token,使用localStorage缓存一下,然后在vuex里面去获取,通常情况这个token会延迟到凌晨3点再去失效,半夜使用的人比较少,第二天的话如果还在某个页面,那么就会需要重新登入。
3. 之前有没有使用cookie处理token?cookie的话很少用了,他们本质都是用来存储的,但是cookie的话服务端是可以操控它的,这种情况下,与其使用cookie让服务端介入,倒不如直接把token保存在localStorage里面,和服务端尽量从业务上分隔开,这也是前后端分离的核心逻辑。
10.3 权限管理和动态路由权限实现思路?
1. 我们内部把这些权限分为了三类,第一类是功能权限(页面权限),第二类是按钮权限,第三类是接口权限。
2. 用户进行登入之后,服务端返回一个权限的数据,然后通过vue-router里面动态路由的概念addRoutes,把动态路由给插进去,左边的菜单栏就有数据可以渲染,那么所谓的一级菜单,二级菜单只要有树形结构很容易渲染出来。
3. 按钮权限,登入拿到的权限数据就包含了按钮的数据,通过v-if去隐藏
4. 接口权限,一般是和按钮权限配合着用的,大多数服务端去进行处理就可以了。
10.4 token过期怎么处理?
token过期的话,请求接口服务端会给我们返回401,并且文字提示中包含过期,我们根据这个在请求的响应拦截器中去清除token,跳转到登录页
10.5 项目优化
1. 打包优化:
2. 首屏优化:
3. 懒加载优化:(图片+数据)
10.6 vue样式中scope属性,怎么实现私有化?
scope 的本质是基于 HTMLCSS属性选择器,分别添加 data-v-xxx属性;
具体来说是通过 vue-loader 实现的,可大致分为三步:
1. 先通过vue-loader解析 vue组件,提取 template、script、style 对应代码块;
2. 然后构造组件实例,在组件实例的选项上绑定scopedId;
3. 最后对style的css代码进行编译转化,应用scopedId生成选择器的属性;
11. 补充vue原理
1. Vue中的更新是同步还是异步?

数据的更新是同步的,视图的更新是异步的,因为视图同步更新的话,会造成多次渲染,影响性能。

2. Vue中 nextTick的原理是什么?

因为视图是异步更新的,外界可能在更新数据之后,拿到最新的dom元素进行操作,这个时候就可以使用nextTick。vue2中nexttick向下做了兼容,支持的话可以使用 promise.then()、MutationObserver、setImmediate,不支持可以用setTimeout()。vue3则放弃了兼容,直接使用promise.then()。

3. 生命周期的原理?

将所有的钩子函数以字符串的方式放入到数组中,然后合并的时候会将外部存在的钩子重写成函数,采用先进先出的方式来管理钩子函数,当外部调用钩子函数时候,会触发callHooks函数,内容会按顺序依次调用,并且将钩子函数内部的this修改为vue的实例。

4. watch的原理?

当key值发生变化的时候,会调用对应的handle函数。深一点的我不清楚

5. computed的原理?

它具有缓存的功能,当某个数据发生改变时,Object.defineProperty中的get和set就会重新执行,当某个数据没有变化时,会返回上一次计算的值(缓存)

6. vue中的数组的响应式如何处理?

数组和对象的处理是不一样的,对象会进行遍历,将里面每一个值都定义成响应式,而数组是通过重写数组的7个方法来进行响应式处理:

push(最后添加)、pop(最后删除)、unshift(最前面添加)、shift(最前面删除)、reverse(反转)、sort(排序)、splice(删除)

7. 给对象新增一个属性 /或者 给数组下标进行赋值,页面会更新吗?

由于Object.defineProperty只对读取跟修改有响应式变化,新增的变化是非响应式的,可以通过 $set 、Vue.set 、数组的话可以使用7个方法

(Vue.set是将set函数绑定在vue的构造函数上,this.$set是将set函数绑定在Vue原型上)

8. Vue.set(target,key,value)和this.$set的原理?

如果目标是一个数组的话,并且你传入key是一个索引,那么内部会做以下事情

  1. 修正数组的length,可能进行删除/新增操作

  2. 调用数组的splice方法进行更新,splice已经重写

  3. 返回value

如果目标是一个对象,是一个新增操作,内部会做以下事情

  1. 调用defineReactive函数,内部用object.defineProperty将数据定义成响应式

  2. 通过watcher更新页面

  3. 返回value

9 vue中的data为什么要是一个函数?

组件中的data写成一个函数,这样每次复用组件的时候,都会返回一份新的data,相当于每个组件实例都有自己私有的数据空间,它们只负责维护各自的数据,不会造成混乱。而写成对象形式,所有组件实例就共用一个data,数据会混乱。

10. vue中name属性的好处?

让组件自己记录自己:

1.便于开发工具调试;

2.项目中使用到keep-alive时候,会把缓存组件实例,如果想要刷新进入 可以使用 exclude=‘name’,这样改组件就不会进入缓存;

3.可以被当成递归组件来使用;

11. 发送请求一般在哪个生命周期?

一般放在mounted中;有些需要根据业务场景去处理,比如父子组件中需要先加载子组件数据,再去渲染父组件数据,那么这个时候就要把父组件放在mounted中去执行。生命周期父前3子前4父mounted

12. Computed和Watch区别?
  1. computed计算属性,依赖其他属性值,并且存在缓存,它依赖的属性值发生改变,才会重新计算computed的值,否则用缓存值。

  2. watch监听,每当监听的数据发生变化时,就会执行回调进行后续操作。

当我们需要在数据变化时,需要执行异步操作,就使用watch,它允许我们执行异步操作。

13.v-model的原理?

用来进行双向绑定的,即可以作用表单元素,也可以作用自定义组件,实质是一个语法糖,会生成一个属性和事件。

作用于输入文本框,生成 value属性和input事件

作用域单项/多选框,生成 checked属性和change事件

作用域自定义组件,生成value属性和input事情。

14.vue中响应式数据的原理?
  1. 首先实现一个监听器(Observer),对数据对象进行遍历,包括子属性对象,利用 Object.defineProperty() 对属性都加上setter和getter 。读取对象某个属性就触发getter,给对象的某个属性赋值的话,就会触发setter,那么就能监听数据变化。
15. vue中模板编译的原理?

模板会先转换为AST抽象语法树,然后把AST转换为可执行的render函数,最后才生成真实DOM。

16. vue中使用了哪些设计模式?

发布订阅模式,单例模式,观察者模式,代理模式

17. VVM的理解?MVC区别?
  1. m–>model数据, v–>view视图, vm–>ViewModel(vue实例对象,将视图中状态和用户行为分离出,只关心数据和业务的处理)

  2. c–>controller(控制器)

18. vue中性能优化?
  1. 合理设置key值,如果只是渲染,可以用index,如果涉及新增/修改,那么要用唯一标识来作为key。

  2. 使用懒加载组件。

  3. 合理使用keep-alive组件。

  4. 数据层次不能太深,合理设置响应式数据。

  5. v-if和v-show的选择。

你可能感兴趣的:(vue,面试,前端,javascript)