vue2面试题:公司真实vue2面试题整理

vue2面试题:公司真实vue2面试题整理_第1张图片

编辑排版 | 宋大狮

平台运营 | 小唐狮

一、说一下vue2的生命周期?

    创建:

        beforecreate:

            实例创建前

            此阶段的data、methods、computed、watch的数据和方法不能被访问

        created:

            实例创建完成后

            此阶段完成数据监听,可以使用数据、更改数据。无法与Dom进行交互,想要的话可以通过nextTick来访问。

    挂载:

        beforeMount:

            页面渲染前

            此阶段虚拟Dom已经创建完成,即将开始渲染。在此时也可以对数据进行更改,不会触发updated。

        mounted:

            页面渲染完成后

            此阶段真实Dom渲染完毕,数据完成双向绑定,可以访问到Dom节点,使用$refs属性对Dom进行操作。

    更新:

        beforeUpdate:

            响应式数据更新前

            此阶段更改数据,不会造成页面重新渲染。

        updated:

            响应式数据更新完成后

            避免在此阶段更改数据,因为这可能会导致无限循环的更新。

    销毁:

        beforeDestroy:

            实例销毁前

            我们可以在这时进行善后收尾工作,比如清除定时器、解除绑定事件

        destroyed:

            实例销毁完成后

    缓存:

        activited:

            keep-alive专属,组件被激活时调用

        deactivited:  

            keep-alive专属,组件被销毁时调用

    1、异步请求放在created还是mounted:

        如果是单单的一个父级组件,放哪里都无所谓。

        如果涉及到了要控制子父组件先后显示正确内容的时候,就可以考虑下父组件的请求要放在哪个钩子里了。想要子组件先拿到数据渲染就放在mounted中,想要父组件先拿到数据就放在created中。

    2、第一次加载页面触发了创建、挂载生命周期

    3、父子组件生命周期执行顺序:

        组件渲染的顺序是先父后子,渲染完成的顺序是先子后父

        组件更新的顺序是先父后子,更新完成的顺序是先子后父

        组件销毁的顺序是先父后子,销毁完成的顺序是先子后父

二、说一下v-show、v-if、v-for的理解?

    v-show和v-if的区别:

        v-if:通过操控DOM增删来实现显示隐藏,不适合频繁切换,数据多不建议用v-if,每一次切换则重新消耗性能

        v-show:修改元素的display实现显示隐藏,适合频繁切换,只在第一次渲染时消耗性能

    v-if和v-for的优先级:

        当v-if与v-for一起使用时,v-for比v-if优先级高,如果连用的话会把v-if给每个元素都添加一下,会造成性能问题,所以不推荐v-if和v-for在同一个标签中同时使用。

        解决办法:在计算属性中,将v-if中的判断转化成对v-for数组的过滤

    v-for中key的作用?

        key代表的是唯一,作用是更高效的更新虚拟dom,diff算法时便于区分新旧虚拟dom,新旧虚拟dom的key相同时不会重新渲染,提高性能

        为何不推荐index作为key值:当以数组下标index作为key值时,当其中一个元素发生了变化(增删改查),就有能导致所有的元素的key值发生改变,导致更新dom时浪费性能

三、说一下组件通信有哪些方式?

    父传子

        1、自定义属性 + props:在父组件中,给子组件绑定一个自定义属性,在子组件中,通过props进行接收

        2、$parent:直接访问父组件实例的属性和方法

        3、$attrs:在父组件中,给子组件绑定一个自定义属性,在子组件中,通过$attrs进行接收【与props不能共存】

        4、插槽

    子传父

        1、$emit + 自定义事件:在父组件中,给子组件绑定一个自定义事件,绑定事件的值为接收参数的函数,在子组件中,通过$emit发送数据

        2、$refs:直接访问子组件实例的属性和方法

        3、$children:直接访问子组件实例的属性和方法【返回数组,必须遍历赋值后才能渲染】

    祖传孙

        1、provide函数传,inject数组收

        2、自定义属性 + v-bind="$attrs"【中间人】 + $attrs

    孙传祖

        1、$emit + v-on="$listeners"【中间人】 + 自定义事件

    兄弟间

        1、$bus 全局事件总线:给vue原型添加一个vue实例,用this.$bus.$emit发送,用this.$bus.$on接收

        2、Vuex

        3、pubsub 发布订阅

    路由传参

        params传参(地址栏不显示参数)

        query传参(地址栏显示参数)

四、watch和computed的区别

    computed计算属性:

        1、如果一个数据需要经过复杂计算就用computed

        2、支持缓存,只有依赖数据发生改变时,才会重新进行计算

        3、不支持异步,当计算属性内有异步操作时,无法监听到数据的变化。原因:定义的函数接收return的结果,return属于同步执行的,是没办法拿到异步请求结果的

        4、计算属性只能取不能存,即不能对计算属性直接赋值。如需要存,要给计算属性手动添加setter

    watch监听器:

        1、如果一个数据需要被监听并且对数据做一些操作就用watch

        2、不支持缓存,数据变化会直接触发相应的操作

        3、支持异步

        设置deep:true  开启深度监听,如果监听的是对象类型,当手动修改对象的某个属性时,可以被监听到

        设置immediate:true  watch初始化时会立即执行一次handler方法

五、说一下为什么data是一个函数?

    data必须是函数,是为了保证不同组件的独立性和可复用性,防止不同组件实例间data的引用关系,避免变量污染

六、说一下什么是路由守卫?

    是路由跳转前、后的一些钩子函数

    分类:

        全局守卫:【写在main.js中 或 router文件夹下的index.js中】

            beforeEach: 进入路由之前的验证(常用,如:判断用户是否登录)

            afterEach: 路由进入之后的验证(常用,如:修改页面标题)

        局部守卫:【写在路由组件内单独的守卫】

            beforeRouteEnter: 进入路由之前的验证

            beforeRouteLeave: 离开路由之前的验证(常用,离开当前页面提示是否保存内容)

            beforeRouteUpdate: 组件路由更新前的验证

        独享守卫:【相当于写在路由配置里的全局守卫,只有前置守卫】

            beforeEnter:进入路由之前的验证

    三个参数:

        to: 要进入的路由对象

        from: 要离开的路由对象

        next: 放行函数

七、说一下路由传参方式query和params的区别?

    1、传参方式

        query通过path进行跳转传参,接收的时候通过this.$route.query进行接收   

        params通过name进行跳转传参,接收的时候通过this.$route.params进行接收

    2、安全性

        params传值不会显示到地址栏,安全性高,但页面刷新数据会丢失

        query传值会暴露在地址栏,页面刷新不会丢失

八、说一下路由模式hash和history的区别?

    在单页面应用SPA中,路由描述的是URL与视图之间的映射关系,这种映射是单向的,即URL变化引起视图更新(无需刷新页面)。  

    1、hash模式

        原理:

            用 url + #后面的hash值 来模拟一个完整的url,直接刷新页面不会导致浏览器向服务器发出新的请求,路由切换时不会

            当调用$router.push方法,会改变hash值触发hashchange事件,前进到指定的url。vue-router会根据url做路由匹配来修改页面内容,实现路由切换的效果

            改变hash值触发hashchange事件,hashchange事件对象中会记录变化的url。点击浏览器的前进后退,会改变hash值,实现路由切换的效果

        特点:

            地址栏有#,影响美观,直接刷新页面不会报404

2、history模式

        原理:

            用 url + 路径 真正实现一个完整的url,直接刷新页面会导致浏览器向服务器发出新的请求,路由切换时不会

            当调用$router.push方法,会改变路径调用pushState方法,前进到指定的url。vue-router会根据url做路由匹配来修改页面内容,实现路由切换的效果

            改变路径调用pushState方法,pushState方法中会记录变化的url。点击浏览器的前进后退 或者 手动调back、forward、go方法,会触发popstate事件,实现路由切换的效果

        特点:

            地址栏没有#,不影响美观,直接刷新页面会报404,需要后端在Nginx中做代理地址的配置

九、说一下对keep-alive的理解?

    缓存组件,减少请求次数

    根据条件缓存页面的方式:

        :include="['组件name']"  指定想要缓存的组件,其他组件不缓存

        :exclude="['组件name']"  指定不想要缓存的组件,其他组件缓存

        利用路由的元属性meta,配合v-if动态判断

    两个钩子函数:

        activated():进入这个缓存组件时触发

        deactivated():离开这个缓存组件时触发

十、说一下对vuex的理解?

    五种状态:

        state: 存储公共数据   this.$store.state

        mutations:同步操作,改变store的数据  this.$store.commit()

        actions: 异步操作,让mutations中的方法能在异步操作中起作用   this.$store.dispatch()

        getters: 计算属性   this.$store.getters

        modules: 子模块 

    使用场景:

        用户信息、菜单信息、购物车信息

    解决vuex页面刷新数据丢失问题的方式:

        办法一:将vuex中的数据直接保存到浏览器缓存中(sessionStorage、localStorage、cookie)   

        办法二:在页面刷新的时候再次请求远程数据,使之动态更新vuex数据   

        办法三:在某一组件向后台请求远程数据保存在vuex,并且在页面刷新前将vuex的数据保存至sessionStorage。在另一组件优先使用vuex内的数据,只有刷新后还没取到后台数据,才会从sessionStorage里取。

            优点:每次刷新页面更新sessionStorage,确保数据的安全性。刷新后还没取到后台数据就从sessionStorage中取,防止网络延迟、数据量大时vuex数据丢失问题。

十一、说一下对MVVM的理解?

    M是model,指的是数据层,即data

    V是view,指的是视图层,即template

    VM是viewModel,指的是视图模型,即vue实例,是连接view和model的桥梁。数据和视图不能直接通信,必须经过VM实现通信。

十二、说一下vue2的响应式原理?

    vue2采用数据代理+数据劫持+发布订阅模式的方法。

    在初始化vue实例时,会把data对象和data对象的属性都添加到vm对象中,通过object.defineProperty()进行数据代理,用vm对象的属性来代理data对象的属性,

    并在Observer类中递归遍历data对象,对data对象中的每个属性都进行数据劫持,都指定一个getter、setter。

    例外的,对于数组,不能通过object.defineProperty()进行数据代理,因为监听的数组下标变化时会出现数据错乱问题,所以数组是调用数组重写的原生方法来实现响应式。

    当通过vm对象修改data对象中的属性时,会触发data属性的setter方法,然后触发它Dep实例的notify方法进行依赖分发,通知所有依赖的Watcher实例执行内部回调函数。

    最后会触发renderWatcher回调,会重新执行render函数,重新对比新旧虚拟DOM,重新渲染页面。

    【Watcher回调是异步任务,它的执行会遵循事件循环机制,且重复的Watcher回调不会放到任务队列中,所以多次重复数据更新时,只会重新渲染一次页面】。

    当通过vm对象读取data对象中的属性时,会触发data属性的getter方法,然后触发它Dep实例的depend方法进行依赖收集。

    当data对象中数组元素发生变化时,会调用数组重写的原生方法,然后触发它Dep实例的notify方法进行依赖分发,通知所有依赖的Watcher实例执行内部回调函数。

    最后会触发renderWatcher回调,会重新执行render函数,重新对比新旧虚拟DOM,重新渲染页面。

    当读取data对象中数组元素时,会触发数组的getter方法,然后触发它Dep实例的depend方法进行依赖收集。

十三、说一下v-model数据双向绑定原理?

    是一个语法糖,做了两件事

    v-bind绑定value,更新数据层

    v-on给元素绑定input事件,监听输入框中的内容,当发生改变时来执行一些事情,并更新视图层

十四、说一下$set的作用和原理?

    作用:

        对象:

            响应式原理:通过触发setter实现更新

            对象中后追加的属性、删除已有属性,Vue默认不做响应式处理

            解决:this.$set()

        数组:

            响应式原理:调用重写的原生方法实现更新

            数组中修改某下标的元素、更新length,Vue默认不做响应式处理

            解决:

                1. this.$set()

                2. 使用原生API:push、pop、shift、unshift、splice、sort、reverse

    原理:

        如果目标是数组,直接使用数组的splice方法通知实现更新

        如果目标是对象,先给对象属性用数据代理添加getter、setter,再通过触发setter通知实现更新

十五、说一下虚拟DOM的原理?

    虚拟dom是对真实dom的抽象,本质是JS对象

    在生成真实DOM之前,vue会把模板编译为一个虚拟dom,当里面某个DOM节点发生变动时,通过diff算法对比新旧虚拟DOM,发现不一样的地方直接修改在真实的DOM上

    优点: 

        可以减少DOM操作

        可以跨平台渲染

    缺点:

        严重依赖打包工具

        节点规模过大时,虚拟DOM的稳定性不如原生DOM

十六、说一下vue的模板编译过程?

    1、获取到template

    2、template 转 AST树

        AST树:

            抽象语法树(一个对象的格式)

            源代码的抽象语法结构的树状描述

            用于将vue的指令、语法等 转为 源代码的抽象语法结构

    3、AST树 转 render函数

        render函数:

            返回包含_c、_v、_s函数的字符串

    4、执行render函数 转 虚拟DOM

    5、执行patch方法,通过diff算法对比新旧虚拟DOM,打补丁,生成真实DOM

十七、说一下单页面应用和多页面应用的区别?

    单页面应用(SPA):

        项目只有一个html页面,只向服务器请求一次静态资源,所有页面跳转都是通过路由组件切换完成的

        优点:页面跳转快、组件化开发

        缺点:首屏加载慢、不利于SEO

    多页面应用(MPA):

        项目有多个html页面,每次页面跳转都要向服务器请求静态资源,返回新的html页面

        优点:首屏加载快、利于SEO

        缺点:页面跳转慢

        

十八、说一下CSS预处理器Less和Sass的区别?

    Sass和Less都属于CSS预处理器,都需要编译器编译成css文件运行

    一般常用的功能是:变量、运算符、混合、嵌套层级

    区别:

        1、编译环境不一样

            Sass基于Ruby环境

            Less基于JS环境

        2、变量符不一样

            Less是@,而Sass是$

        3、功能性不一样

            Sass功能性强大,有函数、条件判断、循环遍历、数据结构的概念

            Less没有

十九、说一下对跨域的理解?

    http请求分为两大类:普通http请求(如百度请求)和ajax请求(跨域是出现在ajax请求)

    同源策略:在浏览器发起ajax请求时,当前的网址和被请求的网址协议、域名、端口号必须完全一致,目的是为了防止跨站脚本攻击。

    跨域是浏览器的同源策略导致的,而服务器之间不受同源策略影响!!!

前端本地开发存在跨域,但前端部署到服务器上就不存在跨域了!!!

    解决方式:

        1、CORS跨域资源共享

        在配置类中,添加一个CORS的过滤器,在响应头上添加允许访问的请求源 addAllowedOrigin("*")

        2、Jsonp

        利用srcipt标签的src属性来实现,前端声明好一个函数,后端返回执行函数,执行函数参数中携带所需的数据。

        可以使用jquery的ajax快速实现Jsonp。

        使用jsonp只能解决get请求的跨域,因为script标签中的src请求就是get请求。

        3、vue脚手架正向代理

        跨域解决:vue脚手架自动在本地开启一个基于node的代理服务器,IP和端口号与本地浏览器相同

        浏览器【http://localhost:8080】 -> 本地代理服务器【http://localhost:8080】 -> 目标服务器【http://47.94.222.12:8080】

        4、Nginx反向代理

        跨域解决:location配置中,在响应头上添加允许访问的请求源 Access-Control-Allow-Origin:*

        浏览器【http://localhost:8080】 - Nginx代理服务器【添加放行请求源】 - 目标服务器【http://192.168.0.120:8080】

二十、说一下nextTick的使用场景和原理?

    等待DOM更新后,再执行内部传入的回调函数

    使用场景:  

        created中想要获取DOM

        响应式数据变化后获取DOM更新后的状态,如 获取列表更新后的高度

    原理: 

        把nextTick回调方法放在renderWatcher回调之后执行,这样就能拿到更新后的DOM

二十一、说一下对单向数据流的理解?

    概念:父级给子组件是啥,子组件可以用,也可以不用,但是不能修改【单向数据流针对于组件通信】

    

    作用:保证了数据的可控性,方便预测和调试

    注意:Vue中的单向数据流是针对基本数据类型,而引用类型是对数据地址的引入,子组件修改数据,父组件能接收到数据的更改

    应用:

        父子传参:子组件不能直接修改父组件的数据,要么通过props从父组件传递过来,要么通过emit在父组件中修改

        vuex:改变store中的状态state的唯一途径就是显式地提交mutation,不能直接修改state

- END -

 

你可能感兴趣的:(面试题合集,前端,javascript,vue.js,css,html)