关于javascript:面试题整理之Vue篇

39次阅读

共计 14026 个字符,预计需要花费 36 分钟才能阅读完成。

又快到年底了,有很多小伙伴可能会抉择跳槽或者升职或者考核,尤其重要的是面试,在面试过程中面试官总会问一些基础性的内容来考查咱们的专业知识的把握水平,再决定是否录用。

前言

当初对于前端来说,问的最多的可能是 JavaScript 根底,除此之外问的更多的就是目前的支流框架相干的一些知识点。目前支流的框架 Vue、React、Angular,国内的互联网状况来讲,目前还是Vue 居多。

就目前来看越来越多的面试,和之前的面试不太一样了,两三年前问的更多的是对于支流框架的利用,目前更多的是对于底层的一些问题更多一些。针对这些 Vue 相干面试题做一下总结并记录。心愿能够帮到更多的小伙伴。

根底面试题

根底面试题即 Vue 利用和应用方面的面试题,这一部分大多数还是面向于高级工程师,相对来说要简略一些。

问:Vue 生命周期钩子都有哪些?

答:Vue生命周期一共有 10 个:

  1. beforeCreate – 在实例初始化之前调用,在此生命周期中是不存在 this 的,因为 Vue 实例还没有创立。
  2. created – 实例初始化之后调用
  3. beforeMount – 在挂载开始之前被调用,如果是在服务器端渲染时不被调用,因为元素还没有渲染,在此申明周期无奈获取到 DOM 元素。
  4. mounted – 在挂载后被调用,是能够获取元素,并进行操作
  5. beforeUpdate – 视图层数据更新前调用,在虚构 DOM 更新之前,能够获取到 DOM j 节点,然而此节点为更新之前的DOM 节点
  6. updated – 视图层数据更新后调用,此处获取到的 DOM 节点是更新之后DOM
  7. beforeDestroy – 实例销毁之前调用,在被销毁的组件中进行调用
  8. destroyed – 实例销毁后调用

beforeDestroydestroyed 生命周期阶段能够在此阶段,进行 `Vuex 数据重置,勾销事件监听等操作,晋升性能。

以上是比拟罕用的生命周期钩子函数,还有两个比拟非凡的生命周期钩子,别离是 activateddeactivated,这两个生命周期只有在组件上应用了 keep-alive 之后才会被执行。

  1. activated – 实例被激活时应用,用于反复激活一个实例的时候,该生命周期于会在 mounted 之后执行。
  2. deactivated – 实例没有被激活时

问:父组件和子组件生命周期钩子函数执行程序?

答:

Vue的父组件和子组件生命周期钩子函数执行程序能够归类为以下 4 局部:

加载渲染过程
  1. 父 beforeCreate
  2. 父 created
  3. 父 beforeMount
  4. 子 beforeCreate
  5. 子 created
  6. 子 beforeMount
  7. 子 mounted
  8. 父 mounted
子组件更新过程
  1. 父 beforeUpdate
  2. 子 beforeUpdate
  3. 子 updated
  4. 父 updated
父组件更新过程
  1. 父 beforeUpdate
  2. 父 updated
销毁过程
  1. 父 beforeDestroy
  2. 子 beforeDestroy
  3. 子 destroyed
  4. 父 destroyed

问:在哪个生命周期内调用异步申请?

答:

能够在钩子函数 createdbeforeMountmounted 中进行调用,因为在这三个钩子函数中,data曾经创立,能够将服务端端返回的数据进行赋值。举荐在 created 钩子函数中调用异步申请,因为在 created 钩子函数中调用异步申请,因为能更快获取到服务端数据,缩小页面 loading 工夫,ssr不反对 beforeMountmounted 钩子函数,所以放在 created 中有助于一致性。

问:父组件能够监听到子组件的生命周期吗?

答:

能够的,有两种办法能够能够做到,第一种则是应用 $emit 自定义事件进行事件监听,当子组件执行到某个生命周期时用 $emit 告诉即可。第二种应用 @hook: 生命周期名称@hook 办法不仅仅是能够监听 mounted,其它的生命周期事件,例如:createdupdated 等都能够监听。

问:keep-alive 是做什么的?

答:keep-aliveVue 内置的一个组件,能够使被蕴含的组件保留状态,防止从新渲染,其有以下个性:

  1. 个别联合路由和动静组件一起应用,用于缓存组件
  2. 提供 includeexclude属性,两者都反对字符串或正则表达式,include示意只有名称匹配的组件会被缓存,exclude示意任何名称匹配的组件都不会被缓存,其中 exclude 的优先级比 include
  3. 对应两个钩子函数 activateddeactivated,当组件被激活时,触发钩子函数activated,当组件被移除时,触发钩子函数deactivated

问:组件之间的传值通信形式有哪些?

答:组件间通信形式有 7 种:

1. props/emit

父组件传入属性,子组件通过 props 接管,能够通过这种办法获取到父组件传入的参数。而子组件则是能够通过 $emit('工夫名', 参数) 像外裸露一个自定义事件,在父组件中的属性监听事件,同时也能获取子组件传进去的参数,应用 v-on: 事件名称 =func 或者 @事件名称 =func 的形式监听子组件的自定义事件。

还能够通过 prop 接管函数为参数,子组件调用该函数,子组件执行函数时,能够传入对应的实参,在父组件接管时以形参的模式接管,执行对应的逻辑,能够达到通信的目标。

2. EventBus

EventBus又称为事件总线,EventBus来作为沟通桥梁能够使任意两个组件之间通信,就像是所有组件共用雷同的事件核心,能够向该核心注册发送事件或接管事件。

如何应用 EventBus,应用new Vue 的形式取得 Vue 实例,本质上 EventBus 是一个不具备 DOM 的组件,它具备的仅仅只是它实例办法而已,因而它十分的轻便。

能够把获取到 Vue 实例挂载到 Vue.prototype 中也能够寄存到一个独自的 js 文件中导出,应用哪种取决于业务的具体情况,个别举荐应用第二种办法。

应用 EventBus.$emit("事件名称", 参数); 的形式进行事件公布。应用 EventBus.$on("事件名称", func) 的办法对事件进行订阅。func的参数则是对应事件传递过去的参数。

EventBus的原理是把注册的事件存起来,等触发事件时再调用。定义一个类去处理事件。

3. Vuex 状态治理

VuexVue 的外围插件、用于任意组件的任意通信,需注意刷新后有可能 Vuex 数据会失落。

创立全局惟一的状态治理仓库 store,有同步mutations、异步actions 的形式去治理数据,有缓存数据 getters,还能分成各个模块modules 易于保护

4. ($parent|$root)/$children

这种通信形式举荐应用,这样会使两个组件之间强耦合在一起,对于当前的保护和拓展来说不不是特地的敌对。

通过 ($parent|$root)/$children 获取到对应的组件实例,调用组件外部的办法以达到通信的成果。

5. $ref

通过 $ref 援用的形式获取子节点,罕用于父组件调用子组件的办法,在 $refs 来存储以后所有设置了 ref 属性的组件的实例,在实例中能够调用到组件外部的办法。

6. attrs/listeners

$attrs能够获取父组件传进来但没有通过 props 接管的属性,能够应用 v-bind="$attrs" 的模式持续向子组件传递参数。

$listeners会开展父组件的所有监听的事件,一个页面中有两个组件的点击事件触发办法是一样的。能够应用 v-on="$listeners" 把事件持续向子组件传递事件。

7. provide/inject

父组件中通过 provider 来提供变量,而后在子组件中通过 inject 来注入变量。只有在父组件中调用了,那么在这个父组件失效的生命周期内,所有的子组件都能够调用 inject 来注入父组件中的值。

问:watch 和 computed 有什么区别?

答:

computed是计算属性在应用时和 data 对象中的数据属性是相似的,watch是用于监听某一个属性的变动的,computed善于的是一个数据受多个数据影响,然而 watch 是用于监听某一个属性的变动的。

computed反对缓存只有依赖数据产生扭转,才会从新进行计算,computed基于它们的响应式依赖进行缓存的,也就是基于 data 中申明过或者父组件传递的 props 中的数据通过计算失去的值,watch则不反对缓存,数据变,间接会触发相应的操作。watch的函数接管两个参数,第一个参数是最新的值;第二个参数是输出之前的值;

computed不反对异步,computed内有异步操作时有效,无奈监听数据的变动,watch反对异步。

computed在应用时,computed属性值是函数,那么默认会走 get 办法,函数的返回值就是属性的属性值,在 computed中的,属性都有一个 get 和一个 set 办法,当数据变动时,调用 set 办法。watch在应用时,监听数据必须是 data 中申明过或者父组件传递过去的 props 中的数据,当数据变动时,触发其余操作,函数有两个参数。immediate(组件加载立刻触发回调函数执行),deep(深度监听)为了发现对象外部值的变动,简单类型的数据时应用。

computed外部就是依据 Object.definedProperty() 实现的,computed具备缓存性能,依赖的值不发生变化,就不会从新计算。watch是监控值的变动,值发生变化时会执行对应的回调函数,computedwatch 都是基于 Watcher 类来执行的。computed缓存性能依附一个变量 dirty,示意值是不是脏的默认是 true,取值后是false,再次取值时dirty 还是 false 间接将还是上一次的取值返回。

问:为什么 data 必须是一个工厂函数而不能是一个对象?

答:

因为 Vue 组件复用准则,因为 data 是对象为援用类型,当一个组件的数据扭转后另一个组件状态会受到影响,然而通过工厂函数的模式返回对象就不会导致这样的问题,因为每个工厂函数所返回的对象都是一个全新的对象绝对独立。

问:Vue 中 style scoped 有作用?

答:

vue 文件中的 style 标签上,有一个非凡的属性:scoped。当一个 style 标签领有 scoped 属性时,它的 CSS 款式就只能作用于以后的组件,也就是说,该款式只能实用于以后组件元素。通过该属性,能够使得组件之间的款式不相互净化。scoped会在 DOM 构造及 css 款式上加上唯一性的标记 data-v-something 属性,即 CSS 带属性选择器,以此实现相似作用域的抉择形式,从而达到款式私有化,不净化全局的作用。scoped应用尽管不便然而咱们须要慎用,因为在咱们须要批改公共组件(三方库或者我的项目定制的组件)的款式的时候,scoped 往往会造成更多的艰难,须要减少额定的复杂度。应用 >>> 能够穿透 scoped 属性,批改其余第三方组件的款式。应用 sassless的款式穿透/deep/

问:v-show 与 v -if 有什么区别?

答:

v-if是真正的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建,v-if是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。v-show就简略得多——不论初始条件是什么,元素总是会被渲染,并且只是简略地基于 CSSdisplay属性进行切换。所以,v-if实用于在运行时很少扭转条件,不须要频繁切换条件的场景,v-show则实用于须要十分频繁切换条件的场景。

问:当给 data 中的对象或数组数据产生变更数据没有视图没有响应是什么起因?

答:

因为在 Vue 在初始化时,会对 data 中的数据应用 object.defineproperty 对数据进行挟持,通过 get/set 实现数据响应的操作,因为增加的属性,在 Vue 在初始化时该属性不存在于 data 中,所以该属性没有挟持到无奈执行 get/setVue 提供过 this.$set 办法能够对新减少的数据挟持实现数据相应。

问:SPA 和 SSR 有什么区别

答:

SPA利用是当初最罕用的开发模式即单页面利用,页面整体式 javaScript 渲染进去的,称之为客户端渲染 CSRSPA 渲染过程由客户端拜访 URL 发送申请到服务端,返回 HTML 构造 (然而SPA 的返回的 HTML 构造是十分的小的,只有一个根本的构造)。客户端接管到返回后果之后,在客户端开始渲染 HTML,渲染时执行对应javaScript 最初通过 JavaScript 渲染成 HTML,渲染实现之后再次向服务端发送数据申请,留神这里时数据申请,服务端返回json 格局数据。客户端接收数据,而后实现最终渲染。

SSR渲染流程是这样的,客户端发送 URL 申请到服务端,服务端读取对应的 URL 的模板信息,在服务端做出 HTML 和数据的渲染,渲染实现之后返回 HTML 构造,客户端这时拿到的之后首屏页面的 HTML 构造。所以用户在浏览首屏的时候速度会很快,因为客户端不须要再次发送 ajax 申请。并不是做了 SSR 咱们的页面就不属于 SPA 利用了,它依然是一个独立的 SPA 利用。

SSR是处于 CSRSPA利用之间的一个折中的计划,在渲染首屏的时候在服务端做出了渲染,留神仅仅是首屏,其余页面还是须要在客户端渲染的,在服务端接管到申请之后并且渲染出首屏页面,会携带着残余的路由信息预留给客户端去渲染其余路由的页面。

SSR 长处:

  1. 更好的 SEO,搜索引擎爬虫爬取工具能够间接查看齐全渲染的页面
  2. 更宽的内容达到工夫(time-to-content),当权申请页面的时候,服务端渲染完数据之后,把渲染好的页面间接发送给浏览器,并进行渲染。浏览器只须要解析 html 不须要去解析javaScript

SSR 毛病:

  1. 开发条件受限,Vue组件的某些生命周期钩子函数不能应用
  2. 开发环境基于Node.js
  3. 会造成服务端更多的负载。在 Node.js 中渲染残缺的应用程序,显然会比仅仅提供动态文件 server 更加占用 CPU 资源,因而如果你在意料在高流量下应用,请筹备响应的服务负载,并理智的采纳缓存策略

问:vue-router 有几种模式?

答:

vue-router公共三种模式:hashhistoryabstract

hash 模式:
  1. hash值是 url#及前面的局部
  2. hash值扭转不会引起页面刷新
  3. hash值的扭转会触发 hashchange 事件
history 模式:
  1. 利用 history.pushState 来实现 url 跳转而无需刷新页面
  2. 须要后盾配置反对,如果 URL 匹配不到任何动态资源,服务器应该返回利用依赖的 index.html 页面
abstract 模式:
  1. 实用于所有 JavaScript 环境,例如服务器端应用Node.js
  2. 没有浏览器API,路由器将主动被强制进入此模式
  3. 这个历史记录的次要目标是解决 SSR, 通过调用router.pushrouter.replace将该地位替换为启动地位

问:$route 和 $router 的区别?

答:

$router

通过 Vue.use(VueRouter)Vue构造函数失去一个 router 的实例对象,这个对象中是一个全局的对象,他蕴含了所有的路由,蕴含了许多要害的路由信息,还有路由的跳转办法,钩子函数等。

$route

$route是一个跳转的路由对象,每一个路由都会有一个 $route 对象,是一个部分的对象,能够获取对应的 namepathparamsquery 等。路由对象的属性是只读的,外面的属性是 immutable(不可变) 的,不过能够应用 watch 监测路由的变动。

问:vue-router 守卫都有哪些?

答:

vue-router守卫主分为三类守卫别离是:全局守卫、路由守卫和组件守卫

全局守卫

全局守卫字面量了解就是定义在全局钩子函数,当路由触发跳转操作时则会触发对应的钩子函数,全局守卫有三种:

  1. beforeEach:它在每次导航路由跳转前触发
  2. beforeResolve:所有 组件内守卫 异步路由组件 被解析之后触发
  3. afterEach:路由跳转实现后触发

beforeEach全局前置守卫接管三个参数:

  • to: 行将要进入的指标路由对象
  • from: 以后导航正要来到的路由对象
  • next: 肯定要调用该办法不然会阻塞路由

重点说一下 next 参数,next参数是一个函数,能够不增加,然而一旦增加,则必须调用一次,否则路由跳转等会进行。next参数只有在 beforeEachbeforeResolve两个路由守卫中存在,afterEach因为曾经跳转到了指标路由则没有提供 next 办法。如果间接执行 next 函数则会间接接入 to 所对应的指标路由中。next(false)则会终端以后路由当行,返回 form 路由对应的路由中。在 next 中传入跳转计划 (如:next('/') 或者 next({path:'/'})),则会跳转到对应的地址中。next(error) 则导航会终止,且该谬误会被传递给 router.onError() 注册过的回调。beforeEach能够定义多个,会依据创立顺序调用,在所有守卫实现之前导航始终处于期待中。

路由守卫

路由守卫只有一个 beforeEnter,须要在路由配置上定义beforeEnter 守卫,此守卫只在进入路由时触发,在 beforeEach 之后紧随执行,不会在 paramsqueryhash扭转时触发,beforeEnter路由守卫的参数是 tofromnext,同beforeEach 一样。

组件守卫

组件守卫则是须要定义在组件中的,组件守卫石油三种:

  1. beforeRouteEnter:路由进入组件之前调用,该钩子在全局守卫 beforeEach 和路由守卫 beforeEnter 之后,全局 beforeResolve 和全局 afterEach之前调用,该守卫内拜访不到组件的实例,也就是 thisundefined,也就是他在 beforeCreate 生命周期前触发
  2. beforeRouteUpdate:在以后路由扭转,然而该组件被复用时调用,举例来说,对于一个带有动静参数的门路 /foo/:id,在/foo/1/foo/2之间跳转的时候,因为会渲染同样的 Foo 组件,因而组件实例会被复用。而这个钩子就会在这个状况下被调用。能够拜访到组件实例 this
  3. beforeRouteLeave:导航来到该组件的对应路由时调用,能够拜访组件实例 this

问:vue-router 如何做权限管制?

答:

vue-router权限管制最罕用的办法是在 beforeEach 须要跳转的路由进行管制,如果没有权限则无奈跳转到路由,个别状况下在路由配置的 meta 中增加权限管制字段,当路由产生跳转时,会触发 beforeEach 全局路由守卫,在该守卫中对权限进行甄别即可实现路由权限管制。首次之外还有一种办法,则是应用 addRoutes 办法,动静的向 vue-router 中增加路由配置,在增加配置之前只在路由中注册具备权限的路由信息即可。

问:vue-router 传参有几种形式?

答:

vue-router传参一共有三种形式:

param

param传参须要在配置路由信息的是时候,在路由中注明须要接管的参数 (如:url/:id),其中的id 则是 param 须要传递的参数,须要留神的是当以这种模式传递参数的时候,如果没有传递参数是无奈正确的匹配到路由的。能够在定义参数前增加 ? 则代表该参数可有可无,无论是否传递参数都能正确的匹配到对应的路由。参数前面能够增加正则 如:url/?:id(\\d+),以这种模式增加参数能够限度参数的格局。

当应用 param 的时候,在配置路由信息的时增加 {props:true} 配置项,则传入的 param 参数,在页面的中的 props 中接管到该参数,除了以这种形式接管以外,还能够应用 this.$route.params 中获取到参数。传递 param 参数无论应用 router-link 还是编程式导航,如果是传入的字符串模式,则能够在对应的路由地址前面间接拼接参数即可。如果是以对象的模式,在对象中增加 params 字段,外部对应的是对应的 param 参数即可。

query

queryparam 传参只是有稍微的不同,query传参不须要在路由配置中定义有哪些参数,query是可有可无的不会影响到路由地址的匹配。query的传递参数应用 query 对象或者在地址前面以 ? 的模式进行拼接。接管的时候则是在 this.$route.query 中获取到传递过去的参数。

注:无论是应用 param 还是 query 进行路由传参,当页面刷新的时候,都不会导致参数失落,因为其参数是间接寄存于路由地址中

meta

集体不太倡议应用 meta 这种模式传参,尽管通过操作也是能够实现传参的目标,然而当页面刷新的时候会导致参数的失落,然而,这种传参是隐式传参,用户是无奈得悉的。

应用 meta 传参能够在路由跳转之前,在跳转页面通过 this.$route 获取到以后路由的对象,在路由对象的 meta 中存入对应的参数。而后应用对应的办法进行路由跳转。当跳转实现之后,在指标页面应用 beforeRouteEnter 组件钩子函数,对参数进行接管,尽管 beforeRouteEnter 无法访问到 this,然而在第三个参数即next 中能够传入一个函数作为参数,这个参数中能够拜访到以后组件的实例,在之后在 beforeRouteEnter 的第二个参数 form 中对象中能够读取到 meta 中存储的数据实现传参。

你对 Vuex 是如何了解的?

答:

Vuex是为 Vue 提供的状态管理模式,集中式存贮治理利用的所有组件的状态,并以相应的规定保障状态以一种可预测的形式发生变化。中有五大外围属性:

  1. state:state次要用于存储数据和存储状态,在根实例中注册 store 当前,用 this.$store.state 来拜访到 state 中所存储的数据。存放数据形式为响应式,vue组件从 store 中读取数据,如数据发生变化,组件也会对应的更新。
  2. mutation:更改 Vuexstore中的状态的惟一办法是提交mutation
  3. action:该办法与 mutation 相似,惟一不同的是在 action 所执行的是异步办法。
  4. getter:能够认为是 store 的计算属性,它的返回值会依据它的依赖被缓存起来,且只有当它的依赖值产生了扭转才会被从新计算。
  5. module:将 store 宰割成模块,每个模块都具备 statemutationactiongetter 甚至是嵌套子模块。

当组件进行数据批改的时候咱们须要调用 dispatch 来触发 actions 外面的办法。actions外面的每个办法中都会有一个 commit 办法,当办法执行的时候会通过 commit 来触发 mutations 外面的办法进行数据的批改。mutations外面的每个函数都会有一个 state 参数,这样就能够在 mutations 外面进行 state 的数据批改,当数据批改结束后,会传导给页面。页面的数据也会产生扭转。

因为传参的办法对于多层嵌套的组件将会十分繁琐,并且对于兄弟组件间的状态传递尽管也能够通过其余的办法进行参数传递,可能仍会感到有力。咱们常常会采纳父子组件间接援用或者通过事件来变更和同步状态的多份拷贝。以上的这些模式十分软弱,通常会导致代码无奈保护。所以咱们须要把组件的共享状态抽取进去,以一个全局单例模式治理。在这种模式下,咱们的组件树形成了一个微小的 视图,不论在树的哪个地位,任何组件都能获取状态或者触发行为!另外,通过定义和隔离状态治理中的各种概念并强制恪守肯定的规定,咱们的代码将会变得更结构化且易保护。

底层面试题

这一部分面试题相比下面要绝对难一些,可能间接回升了一个等级,可能须要对 Vue 相干 API 有足够的理解,并且浏览过相干源码的下能力更好的了解。

问:Vue 的两个外围是什么?

答:别离是:数据驱动和组件零碎

数据驱动

Vue数据观测原理在技术实现上,利用的是 ES5Object.defineProperty和存储器属性:gettersetter 可称为基于依赖收集的观测机制,这些 gettersetter对用户来说是不可见的,然而在外部它们让 Vue 可能追踪依赖,在 property 被拜访和批改时告诉变更。外围是 VM,即ViewModel,保证数据和视图的一致性。每一个指令都会有一个对应的用来观测数据的对象,叫做watcher,每个组件实例都对应一个watcher 实例,它会在组件渲染的过程中把 接触 过的数据 property 记录为依赖。getter的时候咱们会收集依赖,依赖收集就是订阅数据变动 watcher 的收集,依赖收集的目标是当响应式数据发生变化时,可能告诉相应的订阅者去解决相干的逻辑。setter的时候会触发依赖更新,之后当依赖项的 setter 触发时,会告诉watcher,从而使它关联的组件从新渲染。

组件零碎

组件零碎是 Vue 的另一个重要概念,因为它是一种形象,容许咱们应用小型、独立和通常可复用的组件构建大型利用。认真想想,简直任意类型的利用界面都能够形象为一个组件树,Vue更心愿构建的页面是由各个组件形成而非html,当开发我的项目时把整个应用程序划分为组件,以使开发更易治理与保护。

组件零碎中蕴含了几个很重要的局部:

  1. template:模板申明了数据和最终展示给用户的 DOM 之间的映射关系。
  2. data:一个组件的初始数据状态。对于可复用的组件来说,这通常是公有的状态
  3. props:组件之间通过参数来进行数据的传递和共享
  4. methods:对数据的改变操作个别都在组件的办法内进行
  5. lifecycle hooks:一个组件会触发多个生命周期钩子函数
  6. assets:Vue.js 当中将用户自定义的指令、过滤器、组件等统称为资源

问:如何了解 MVVM?

答:

MVVM次要由三个局部组成:ModelViewViewModel

  1. Model:代表数据模型,也能够在 Model 中定义数据批改和业务逻辑
  2. View:代表 UI 组件,它负责将数据模型转化成 UI 展示进去
  3. ViewModel:代表同步 View 和 Model 的对象

MVVMViewModel 没有间接的关系,全副通过 ViewModel 进行交互。ViewModel负责把 Model 的数据同步到 View 显示进去,还负责把 View 的批改同步回 ModelMVVM 实质就是基于操作数据来操作视图进而操作 DOM,借助MVVM 无需间接操作 DOM,开发者只需实现蕴含申明绑定的视图模板,编写ViewModel 中有业务,使得 View 齐全实现自动化。

问:Vue 初始化做了什么?

答:

Vue在初始化时会接管用户所传入的 options 即所须要的参数,之后则会创立 Vue 的实例,并且为该实例定义一个惟一的 _uid 的标识,用于辨别 Vue 的实例,把 Vue 实例标记成 Vue 防止被观察者观测到。

实现实例创立的初始化工作之后,须要对用户选项和零碎默认的选项进行合并,首先解决的的是组件的配置内容,把传入的 option 与其构造函数自身进行合并,这里蚕蛹的策略是默认配置和传入配置的配置进行合并。如果是外部组件(子组件)实例化,且动静的 options 合并会很慢,须要对 options 的一些非凡参数进行解决。如果是根组件,将全局配置选项合并到根组件的配置上,其实就是一个选项合并。

接下来则是初始化外围局部,首先初始化 Vue 实例生命周期相干的属性,定义了比方:rootparentchildrenrefs,接着初始化自定义组件事件的监听,若存在父监听事件,则增加到该实例上,而后初始化 render 渲染所需的 slots、渲染函数等。其实就两件事

  1. 插槽的解决、
  2. $createElm 也就是 render 函数中的 h 的申明

接下来则是执行 beforeCreate 钩子函数,在这里就能看出一个组件在创立前和后别离做了哪些初始化。

执行完 beforeCreate 钩子函数之后,初始化注入数据,隔代传参时先 inject。作为一个组件,在要给后辈组件提供数据之前,须要先把祖辈传下来的数据注入进来。对propsmethodsdatacomputedwatch 进行初始化,包含响应式的解决,在把祖辈传下来的数据注入进来当前再初始化provide

最初调用 created 钩子函数,初始化实现,能够执行挂载了,挂载到对应 DOM 元素上。如果组件构造函数设置了 el 选项,会主动挂载,所以就不必再手动调用 $mount 去挂载。

问:如何了解 Vue 的响应式数据?

答:

Vue中实现了一个 definedReactive 办法,办法外部借用 Object.definedProperty() 给每一个属性都增加了 get/set 的属性。definedReactive只能监控到最外层的对象,对于内层的对象须要递归劫持数据。数组则是重写的 7 个 pushpopshiftunshiftreversesortsplice 来给数组做数据拦挡,因为这几个办法会扭转原数组。对象新增或者删除的属性无奈被 set 监听到只有对象自身存在的属性批改才会被劫持。或应用 Vue 提供的 $set() 实现监听,在 defineReactive 中存有一个 Dep 类,这个用来收集渲染的 WatcherWatcher 的次要工作则应用用来更新视图。

问:Vue 如何进行依赖收集?

答:

Dep是一个用来负责收集 Watcher 的类,Watcher是一个封装了渲染视图逻辑的类,用于派发更新的。须要留神的是 Watcher 是不能间接更新视图的还须要联合 Vnode 通过 patch() 中的 diff 算法才能够生成真正的DOM

然而每一个属性都有本人的 dep 属性,来寄存依赖的 Watcher,属性发生变化后会告诉Watcher 去更新。在用户获取 (getter) 数据时 Vue 给每一个属性都增加了dep 属性来 (collect as Dependency) 收集 Watcher。在用户setting 设置属性值时 dep.notify() 告诉收集的 Watcher 从新渲染。Dep依赖收集类其和 Watcher 类是多对多双向存储的关系。每一个属性都能够有多个 Watcher 类,因为属性可能在不同的组件中被应用。同时一个 Watcher 类也能够对应多个属性。

每一个属性能够有多个依赖,比方这个属性可能应用在 computed 中,watch中,自身的 data 属性中。这些依赖都是应用响应式数据的 Dep 来收集的。Watcher 是依赖就像一个中介,可能被 Dep 收集也可能被 Dep 告诉更新。

问:Vue 是如何编译模板的?

答:

编译是把咱们写的 .vue 文件里的 template 标签蕴含的 html 标签变为 render 函数,能够这么了解 template 模板是对 render 的封装,templatevue 源码外面会变转化为 render 函数:

  1. 将 template 模板字符串转换成 ast 语法树(parser 解析器),这里应用了大量的正则来匹配标签的名称,属性,文本等。
  2. 对 AST 进行动态节点 static 标记,次要用来做虚构 DOM 的渲染优化(optimize 优化器),这里会遍历出所有的子节点也做动态标记
  3. 应用 AST 语法树 从新生成 render 函数代码字符串 code。

问:Vue 生命周期钩子实现原理?

答:

Vue中的生命周期钩子只是一个回调函数,在创立组件实例化的过程中会调用对应的钩子执行。应用 Vue.mixin({}) 混入的钩子或生命周期中定义了多个函数,Vue外部会调用 mergeHook() 对钩子进行合并放入到队列中顺次执行。

问:Vue.mixin 应用场景和原理?

答:

Vue.mixin次要用于抽离一个公共的业务逻辑实现复用。其外部执行时会调用 mergeOptions() 办法采纳策略模式针对不同的属性合并。混入的数据和组件的数据有抵触就采纳组件自身的。Vue.mixin({})存在一些缺点,导致混入的属性名和组件属性名产生命名抵触,数据依赖的起源问题。

问:$nextTick 实现原理?

答:

vm.$nextTick(cb)是一个异步的办法为了兼容性做了很多降级解决顺次有 promise.then,MutationObserversetImmediatesetTimeout。在数据批改后不会马上更新视图,而是通过set 办法 notify 告诉 Watcher 更新,将须要更新的 Watcher 放入到一个异步队列中,nexTick的回调函数就放在 Watcher 的前面,期待主线程中同步代码执行借宿而后顺次清空队列中,所以 vm.nextTick(callback) 是在 dom 更新完结后执行的。

问:vue-router 实现原理?

答:vue-router最罕用的模式有两种别离是 hash 模式和 history 模式:

hash 模式

hash模式是 vue-router 的默认路由模式,它的标记是在域名之后带有一个 #,通过window.location.hash 获取到以后 urlhash。·hash·模式下通过 hashchange 办法能够监听 urlhash的变动。hash模式的特点是兼容性更好,并且 hash 的变动会在浏览器的 history 中减少一条记录,能够实现浏览器的后退和后退性能。

history 模式

history模式是另一种前端路由模式,它基于 HTML5history对象,通过 location.pathname 获取到以后 url 的路由地址。history模式下,通过 pushStatereplaceState办法能够批改 url 地址,联合 popstate 办法监听 url 中路由的变动。

问:vuex 实现原理?

答:

Vuex在初始化时,在全局存储了 Vue 的实例,在 install 函数中,首先会判断是否曾经调用了 Vue.use(Vuex),而后调用applyMixin 办法进行初始化的一些操作,applyMixin办法只做了一件事件,就是将所有的实例上挂载一个 $store 对象,在应用 vuex 的时候,会将 store 挂载在根组件之上。在第一次调用 vuexInit 函数时,options.store就是根选项的 store,因而会判断其类型是不是function,若是则执行函数并将后果赋值给根实例的$store 中,否则间接赋值。

Vuexstate 状态是响应式,是借助 vuedata是响应式,将 state 存入 vue 实例组件的 data 中,Vuexgetters 则是借助 vue 的计算属性 computed 实现数据实时监听。

结束语

以上面试题是笔者在面试过程中面试官们问到的做了一些调研学习和整顿,可能会有些许的谬误,大家能够在上面评论指出谬误,大家独特学习提高。如果有哪些方面没有笼罩到的中央大家也能够评论通知我,前面回补齐。

正文完
 0