重整旗鼓,2019自结前端面试小册【Vue.Js】

前言

临近2019年的尾声,是否是该为了更好的2020年再战一回呢? ‘胜败兵家事不期,包羞忍耻是男儿。江东子弟多才俊,卷土重来未可知’,那些在秋招失利的人,难道就心甘情愿放弃吗!css

此文总结2019年以来本人经历以及浏览文章中,较热门的一些面试题,涵盖从CSS到JS再到Vue再到网络等前端基础到进阶的一些知识。html

总结面试题涉及的知识点是对本身的一个提高,也但愿能够帮助到同窗们,在2020年会有一个更好的竞争能力。前端

Module Four - Vue

「About Base」

讲一讲你对MVVM的理解?与MVC有什么不一样?

  • MVC指的是Model-View-Controller,即模型-视图-控制器。
    • 使用MVC的目的就是将模型与视图分离
    • MVC属于单向通讯,必须经过Controller来承上启下,既必须由控制器来获取数据,将结果返回给前端,页面从新渲染
  • MVVM指的是Model-View-ViewModel,即模型-视图-视图模型,「模型」指的是后端传递的数据,「视图」指的是所看到的页面,「视图模型」是MVVM的核心,它是链接ViewModel的桥梁,实现view的变化会自动更新到viewModel中,viewModel中的变化也会自动显示在view,是一种数据驱动视图的模型

区别:vue

  • MVC中的ControlMVVM中演变成viewModel
  • MVVM经过数据来显示视图,而不是经过节点操做
  • MVVM主要解决了MVC中大量的DOM操做,使页面渲染性能下降,加载速度慢,影响用户体验的问题

请说一下Vue响应式数据的原理?

Vue底层对于响应式数据的核心是object.definePropertyVue在初始化数据时,会给data中的属性使用object.defineProperty从新定义属性(劫持属性的gettersetter),当页面使用对应属性时,会进行依赖收集(收集当前组件的watcher),若是属性发生变化,会通知相关依赖进行更新操做node

  • 总结: Vue经过数据劫持配合发布者-订阅者的设计模式,内部经过调用object.defineProperty()来劫持各个属性的gettersetter,在数据变化的时候通知订阅者,并触发相应的回调

讲一讲Vue是如何检测数组的变化?

  • 核心思想:使用了函数劫持的方式,重写了数组的方法(push,pop,unshift,shift···
  • Vuedata中的数组,进行了原型链的重写,指向了本身所定义的数组原型方法,当调用数组的API时,能够通知依赖更新,若是数组中包含着引用类型,会对数组中的引用类型再次进行监控

为何Vue要采起异步渲染?

由于若是不采用异步渲染,那么每次更新数据都会进行从新渲染,为了提升性能,Vue经过异步渲染的方式,在本轮数据更新后,再去异步更新视图面试


「译」Object.defineProperty有什么缺点?(为何Vue3.0开始使用Proxy实现响应式)

  • Object.defineProperty只能劫持对象的属性,所以须要遍历对象的每一个属性,而Proxy能够直接代理对象
  • Object.defineProperty对新增属性须要手动进行观察,因为Object.defineProperty劫持的是对象的属性(第一点),因此新增属性时,须要从新遍历对象,对其新增属性再使用Object.defineProperty进行劫持 (正是这个缘由致使咱们在给data中的数组或对象新增属性时,须要使用$set才能保证视图能够更新)
  • Proxy性能高,支持13种拦截方式

nextTick实现原理是什么? 在Vue中有什么做用

  • 原理:EventLoop事件循环
  • 做用:在下次dom更新循环结束后执行延迟回调,当咱们修改数据以后当即使用nextTick()来获取最新更新的Dom

watch中的deep:true是如何实现的?

当用户指定了watch中的deep:true时,若是当前监控的值是数组类型(对象类型),会对对象中的每一项进行求值,此时会将当前watcher存入到对应属性的依赖中,这样数组中的对象发生变化也会通知数据进行更新vue-router

缺点:因为须要对每一项都进行操做,性能会下降,不建议屡次使用deep:truevuex


为何v-if与v-for不建议连在一块儿使用?

v-for优先级高于v-if,若是连在一块儿使用的话会把v-if给每个元素都添加上,重复运行于每个v-for循环中,会形成性能浪费后端


「译」组件的data为何要写成函数形式

Vue中,组件都是可复用的,一个组件建立好后,能够在多个地方重复使用,而无论复用多少次,组件内的data都必须是相互隔离,互不影响的,若是data以对象的形式存在,因为Javascript中对象是引用类型,做用域没有隔离,所以data必须以函数的形式返回设计模式

  • 总结:为了实现每一个组件实例能够维护独立的数据拷贝,不会相互影响

❗ 小知识: new Vue根组件不须要复用,所以不须要以函数方式返回


「译」v-for中的key的做用是什么?

key是为每一个vnode指定惟一的id,在同级vnodeDiff过程当中,能够根据key快速的进行对比,来判断是否为相同节点,并利用key的惟一性生成map来更快的获取相应的节点,另外指定key后,能够保证渲染的准确性


Vue每一个生命周期何时被调用?

  • beforeCreate → 在实例初始化以后,数据观测(data observer)以前被调用
  • created → 实例已经建立完成以后被调用。在这里,实例已完成如下配置:
    • 数据观测(data observer)
    • 属性和方法的运算
    • watch/event事件回调
    • 但这里尚未$el
  • beforeMount → 在挂载开始以前被调用,相关的render函数首次被调用
  • mounted$el被新建立的vm.$el替换,并挂载到实例上以后调用该钩子
  • beforeUpdate → 数据更新时调用,发生在虚拟DOM从新渲染和打补丁以前
  • updated → 因为数据更改致使的虚拟DOM从新渲染和打补丁,在这以后会调用该钩子(该钩子在服务器端渲染期间不被调用)
  • beforeDestroy → 实例销毁以前调用,在这里,实例仍然彻底可使用
  • destroyedVue实例销毁后调用。调用该钩子后,Vue实例指示的全部东西都会解绑,全部的事件监听器会被移除,全部的子实例也会被销毁(该钩子在服务器端渲染期间不被调用)


Vue每一个生命周期内部能够作什么事?

  • created → 实例已经建立完成,因为它是最先触发的,因此能够进行一些数据,资源的请求
  • mounted → 实例已经挂载完成,能够进行一些DOM操做
  • beforeUpdate → 能够在该钩子中进一步地更改状态,这不会触发附加的渲染过程
  • updated → 能够执行依赖于DOM的操做。但在大多数状况下,应避免在该钩子中更改状态,由于这可能致使更新无限循环
  • destroyed → 能够执行一些优化操做,例如清空定时器,清理缓存,解除事件绑定等

Vue组件有哪些声明生命周期钩子?

beforeCreate」、「created」、「beforeMount」、「mounted」、「beforeUpdate」、「updated」、「beforeDestroy」、「destroyed

❗ 小知识:

<keep-alive>拥有本身独立的钩子函数 activated | deactivated

  • activated → 在被<keep-alive>包裹的组件中才有效,当组件被激活时使用该钩子
  • deactivated → 在被<keep-alive>包裹的组件中才有效,当组件被中止时使用该钩子

「译」Vue的父组件和子组件生命周期钩子执行顺序是什么?

  • 理解渲染过程:

父组件挂载完成必须是等到子组件都挂载完成以后,才算父组件挂载完,因此父组件的mounted确定是在子组件mounted以后

So:「父」beforeCreate → 「父」created → 「父」beforeMount → 「子」beforeCreate → 「子」created → 「子」beforeMount → 「子」mounted → 「父」mounted

  • 子组件更新过程(取决于对父组件是否有影响)

    • 影响到父组件: 「父」beforeUpdate → 「子」beforeUpdate → 「子」updated → 「父」updated
    • 不影响父组件: 「子」beforeUpdate → 「子」updated
  • 父组件更新过程(取决于对子组件是否有影响)

    • 影响到子组件: 「父」beforeUpdate → 「子」beforeUpdate → 「子」updated → 「父」updated
    • 不影响子组件: 「父」beforeUpdate → 「父」updated
  • 销毁过程

    • 「父」beforeDestroy → 「子」beforeDestroy → 「子」destroyed → 「父」destroyed

怎么理解vue的单向数据流

  • vue中,父组件能够经过prop将数据传递给子组件,但这个prop只能由父组件来修改,子组件修改的话会抛出错误
  • 若是是子组件想要修改数据,只能经过$emit由子组件派发事件,并由父组件接收事件进行修改

为何子组件不能够修改父组件传递的Prop?(为何vue提倡单向数据流)

因为vue提倡单向数据流,即父级props的更新会流向子组件,但反过来则不行。这是为了防止意外的改变父组件的状态,使得应用的数据流变得难以理解。若是破坏了单项数据流,当应用复杂时,debug的成本将会很是高


组件间有哪些通讯方式?

  • 父子组件通讯

    • props / event
    • $parent / $children
    • ref
    • provide / inject
    • .sync
  • 非父子组件通讯

    • eventBus
    • 经过根实例$root
    • vuex
    • $attr / $listeners
    • provide / inject

❗ 小知识: 关于.sync的使用

假设有一个组件 comp

<comp :foo.sync="bar"></comp>

传递foo值并用sync修饰,会被扩展成

<comp :foo="bar" @update:foo="val => bar = val"></comp>
复制代码
当子组件comp须要更新foo的值时,它须要显示地触发一个更新事件

this.$emit('update:foo', newValue)
复制代码

说一说vue的动态组件

多个组件经过同一个挂载点进行组件的切换,is的值是哪一个组件的名称,那么页面就会显示哪一个组件

<div :is='xxx'></div>
复制代码

讲一讲递归组件的用法

组件是能够在它们本身的模板中调用自身的,不过它们只能经过name选项来作这件事

首先咱们要知道,既然是递归组件,那么必定要有一个结束的条件,不然就会致使组件无限循环使用,最终出现max stack size exceeded的错误,也就是栈溢出。因此,咱们应该使用v-if = 'false'来做为递归组件的结束条件,当遇到v-if = 'false'时,组件将不会再进行渲染

自定义组件的语法糖v-model是怎么样实现的?(v-model如何实现双向绑定)

v-model本质是v-bindv-on的语法糖,用来在表单控件或组件上建立双向绑定。

<input v-model='searchText'>

等价于

<input
    v-bind:value='searchText'
    v-on:input='searchText = $event.target.value'>
复制代码

在一个组件上使用v-model,默认会为组件绑定名为valueprop和名为input的事件


「译」Vuex和单纯的全局对象有什么区别?

vuex和全局对象主要有两大区别:

  • vuex的状态存储是响应式的。当vue组件从store中读取状态时,若store中的状态发生变化,那么相应的组件也会获得高效更新
  • 不呢能直接改变store中的状态,改变store中的状态惟一方法是显示地提交mutationcommit)。这样使得咱们能够方便地跟踪每个状态的变化

「译」为何vuex的mutation中不能作异步操做?

vuex中全部的状态更新的惟一方式都是提交mutation,异步操做须要经过action来提交mutationdispatch)。这样使得咱们能够方便地跟踪每个状态的变化,从而让咱们可以实现一些工具帮助咱们更好地使用vuex

每一个mutation执行完后都会对应获得一个新的状态变动,这样devtools就能够打个快照存下来,而后就能够实现time-travel了。

若是mutation支持异步操做,就没有办法知道状态是什么时候更新,没法很好的进行状态追踪,影响调试效率


v-show / v-if 的区别是什么?

  • v-if指若是条件不成立则不会渲染当前指令所在节点的Dom元素,会在切换过程当中对条件块的事件监听器和子组件进行销毁和重建
  • v-show只是基于css进行切换,无论条件是什么,都会进行渲染(切换display:block | none

So:v-if切换的开销较大,而v-show初始化的开销较大,因此在须要频繁切换显示和隐藏的Dom元素时,使用v-show更合适,渲染后不多进行切换则使用v-if较合适


computed / watch 的区别是什么?

  • computed是依赖于其余属性的一个计算值,而且具有缓存,只有当依赖的值发生变化才会更新(自动监听依赖值的变化,从而动态返回内容)
  • watch是在监听的属性发生变化的时候,触发一个回调,在回调中执行一些逻辑

So:computedwatch区别在于用法上的不一样,computed适合在模板渲染中,若是是须要经过依赖来获取动态值,就可使用计算属性。而若是是想在监听值变化时执行业务逻辑,就使用watch


computed / methods 的区别是什么?

  • computed是基于它们响应式依赖进行缓存,只有在依赖值发生变化,才会进行计算求值
  • methods每次使用都会执行相应的方法

Vue中 v-html 有什么做用?会致使什么问题?

v-html能够用来识别HTML标签并渲染出去

致使问题: 在网站上动态渲染任意Html,很容易致使受到Xss攻击,因此只能在可信内容上使用v-html,且永远不能用于用户提交的内容上


keep-alive在vue中的做用是什么?

包裹在<keep-alive>里组件,在切换时会保存其组件的状态,使其不被销毁,防止屡次渲染,

· keep-alive拥有两个独立的生命周期(activated | deactivated),使keep-alive包裹的组件在切换时不被销毁,而是缓存到内存中并执行deactivated钩子,切换回组件时会获取内存,渲染后执行activated钩子


如何新增自定义指令?

  • 建立局部指令
var app = new Vue({
    el: '#app',
    data: {    
    },
    // 建立指令(能够多个)
    directives: {
        // 指令名称
        dir1: {
            inserted(el) {
                //  toDo
            }
        }
    }
})
复制代码
  • 建立全局指令
Vue.directive('dir2', {
    inserted(el) {
        // inserted 表示元素插入时
        // toDo
    }
})
复制代码
  • 指令使用
<div id="app">
    <div :dir1='..'></div>
</div>
复制代码

如何自定义过滤器

  • 建立局部过滤器
var app = new Vue({
    el: '#app',
    data: {    
    },
    // 建立指令(能够多个)
    filters: {
        // 指令名称
        newfilter:function(value){
            // toDo
        }
    }
})
复制代码
  • 建立全局过滤器
Vue.filter('newfilter', function (value) {
    // toDo
})
复制代码
  • 过滤器使用
<div>{{xxx | newfilter}}</div>
复制代码

vue经常使用修饰符有哪些,有什么用?

  • .prevent :拦截默认事件
  • .passive :不拦截默认事件
  • .stop :阻止事件冒泡
  • .self :当事件发生在该元素而不是子元素的时候会触发
  • .capture :事件侦听,事件发生的时候会调用

vue等单页面应用优缺点是什么?

  • 优势:vue的目的是经过尽量简单的API实现相应的数据绑定和组合的视图组件,核心是一个响应的数据绑定系统。MVVM,数据驱动,组件化,轻量,简洁,高效,快速。
  • 缺点
    • 不支持低版本的浏览器,最低只支持IE9
    • 不利于SEO的优化
    • 第一次加载首页耗时相对长一些,不可使用浏览器的导航按钮须要自行实现前进和后退

如何让css仅在当前组件中起做用

<style>标签上写入scoped便可


「About Router」

关于路由,route / router 有什么区别?

  • route 表示路由信息对象,包括path,params,hash,query,fullPath,matched,name等路由信息参数
  • router 表示路由实例对象,包括了路由的跳转方法,钩子函数等

「译」 vue-Router中有哪些导航守卫

  • 「全局前置钩子」:beforeEach,beforeResolve,afterEach
  • 「路由独享守卫」:beforeEnter
  • 「组件内部守卫」:beforeRouteEnter,beforeRouteUpdate,beforeRouteLeave

导航解析流程:

  • 导航被触发
  • 在失活的组件里调用beforeRouteLeave离开守卫
  • 调用全局的beforeEach守卫
  • 在重用的组件里调用beforeRouteUpdate守卫
  • 在路由配置里调用beforeEnter守卫
  • 解析异步路由组件
  • 在被激活的组件里调用beforeRouteEnter守卫
  • 调用全局的beforeResolve守卫
  • 导航被确认
  • 调用全局的afterEach守卫
  • 触发Dom更新
  • 用建立好的实例调用beforeRouteEnter守卫中传给next的回调

「译」vue-Router 中 hash / history 两种模式有什么区别?

  • hash模式会在url上显示'#',而history模式没有
  • 刷新页面时,hash模式能够正常加载到hash值对应的页面,history模式没有处理的话,会返回404,通常须要后端将全部页面都配置重定向到首页路由
  • 兼容性上,hash模式能够支持低版本浏览器和IE

「译」 vue-router 中 hash / history 是如何实现的?

  • hash模式
    • #后面hash值的变化,不会致使浏览器向服务器发出请求,浏览器不发出请求,就不会刷新页面,同时经过监听hashchange事件能够知道hash发生了哪些变化。根据hash变化来实现页面的局部更新
  • history模式
    • history模式的实现,主要是Html5标准发布的两个Api(pushStatereplaceState),这两个Api能够改变url,可是不会发送请求,这样就能够监听url的变化来实现局部更新

怎么定义 vue-router 的动态路由?怎么获取传过来的值

  • 动态路由的建立,主要是使用path属性过程当中,使用动态路径参数,以冒号开头
{
    path:'/details/:id',
    name:'Details',
    components:Details
}

# 访问`details`前缀下的路径,例如`details/1`,`details/2`等,都会映射到`Details`这个组件
复制代码
  • 当匹配到/details下的路由时,参数值会被设置到this.$route.params下,因此经过这个属性能够获取动态参数
this.$route.params.id
复制代码

vue-router 传参方式有哪些?

  • 经过params
    • 只能用name,不能用path
    • 参数不会显示在url
    • 浏览器强制刷新会清空参数
  • 经过query
    • 只能用path,不能用name
    • name可使用path路径
    • 参数会显示在url
    • 浏览器刷新不清空参数

「About Vuex」

vuex有什么优缺点?

  • 优势
    • 解决了非父子组件的消息传递(将数据存放在state中)
    • 减小了Ajax请求次数,有些情景能够直接从内存中的State获取
  • 缺点
    • 刷新浏览器,vuex中的State就会从新变回初始化状态

vuex有哪几种属性?

  • Statevuex的基本数据,用来存储变量
  • Getter :从基本数据state派生的数据,至关于state的计算属性
  • Mutation :提交更新数据的方法,必须是同步的(须要异步则使用action)。每一个mutation都有一个字符串的事件类型(type)和一个回调函数(handler
  • Action :和mutation的功能大体相同,不一样在于
    • action提交的是mutation,而不是直接变动状态
    • action能够包含任意异步操做
  • Module :模块化vuex,可让每个模块拥有本身的statemutationactiongetter,使得结构清晰,方便管理

vuex 中的 state 有什么特性?

  • vuex就是一个仓库,仓库里面放了不少对象,其中state就是数据源存放地
  • state里面存放的数据是响应式的,Vue组件从store中读取数据,如果store中的数据改变,依赖这个数据的组件也会更新数据
  • 它经过mapState把全局的stategetters映射到当前组件的computed计算属性中

vuex 中的 getters 有什么特性?

  • getters能够对state进行计算操做,能够把它看作storecomputed计算属性
  • 虽然在组件中也能够作计算属性,但getters能够在多个组件之间复用
  • 若是一个状态只在一个组件内使用,是能够不用getters

Vue 中对 Ajax 请求代码应该写在组件的 methods 中仍是 vuex 的 actions 中?

  • 若是请求的数据是不被其余组件公用的,仅仅在请求的组件内使用,就不须要放入vuexstate
  • 若是被其余地方复用,能够将请求放入action里,方便复用;若是不须要复用这个请求,直接写在Vue文件里会更方便
相关文章
相关标签/搜索