《vuejs高频面试题.docx》由会员分享,可在线阅读,更多相关《vuejs高频面试题.docx(16页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、.什么是vue生命周期vue生命周期的理解vue实例有一个完整的生命周期,生命周期也就是指一个实例从开始 创建到销毁的这个过程 beforeCreate()在实例创建之间执行,数据未加载状态created()在实例创建、数据加载后,能初始化数据,dom渲染之前执 行 beforeMount()虚拟dom已创建完成,在数据渲染前最后一次更改数据mounted。页面、数据渲染完成,真实dom挂载完成 beforeUpadate()重新渲染之前触发updated()数据已经更改完成,dom也重新render完成,更改数据会陷 入死循环 beforeDestory()和destoryed()前者是销毁
2、前执行(实例仍然完全可 用),后者则是销毁后执行作用:生命周期中有多个事件钩子,在控制整个Vue实例的过程时更容易形 成好的逻辑。beforeCreate:完成实例初始化,this指向被创建的实例,data, computed, watch, mothods方法 和 数据都不可以访问,数据观测之前(data observer) 被调用。created:实例创建完成,data, computed, watch, methods 可被访问,未挂 载Dom,可对data进行操作,操作Dom需放到nextTick中。beforeMount:有了 el,找到对应的template编译成render函数m
3、ounted:完成挂载Dom和渲染,可对Dom进行获取节点等操作,可发起后 端请求拿到数据。beforeUpdate:数据更新时调用,发生在虚拟Dom重新渲染 和 打补丁之前之 调用。updated:组件Dom已完成更新,可执行依赖的Dom操作,不要操作数据会陷 入死循环。beforeDestroy:实例销毁之前调用,可进行优化操作,如销毁定时器,解除绑 定事件。destroyed:组件已经被销毁,事件监听器和子实例都会被移除销毁。首页可以控制导航跳转,beforeEach, afte可ach等,一般用于页面title的 修改。一些需要登录才能调整页面的重定向功能。beforeEach 主要有
4、 3 个参数 to, from, next:to: route即将进入的目标路由对象,from: route当前导航正要离开的路由next: function 一定要调用该方法resolve这个钩子。执行效果依赖next方 法的调用参数。可以控制网页的跳转。.vue-router有哪几种路由守卫?1 .全局守卫(vue-router全局有三个守卫)router. beforeEach全局前置守卫 进入路由之前router. beforeResolve 全局解析守卫 5. 0+)在 beforeRouteEnter 调 用之后调用router. afterEach全局后置钩子 进入路由之后/ m
5、ain, js 入口文件import router from ./router ; / 弓|入路由router. beforeEach (to, from, next) = next (););router. beforeResolve (to, from, next) = next (););router. afterEach(to, from) = console, log (? afterEach 全局后置钩子););2 .路由独享守卫const router = new VueRouter ( routes:(path: /foo,component: Foo,beforeEnter:
6、 (to, from, next) = /参数用法什么的都一样,调用顺序在全局前置守卫后面,所以不 会被全局守卫覆盖)3 .路由组件内的守卫beforeRouteEnter进入路由前,在路由独享守卫后调用 不能 获取组件实例this,组件实例还没被创建beforeRouteUpdate (2. 2)路由复用同一个组件时,在当前路由改变,但是该组件被复用时调用 可以访问组件实例thisbeforeRouteLeave离开当前路由时,导航离开该组件的对应路由时调用, 可以访问组件实例this.hash模式和history模式hash:在url中带有#,其原理是onhashchange事件。可以在w
7、indow对象上监听这个事件:window, onhashchange = function(event) history:没有原# ,其原理是popstate事件,需要后台配置支持。html5中新增两个操作历史栈的API: pushState ()和replaceState ()方法。history. pushState (data, title , url) ; / 向历史记录中追加一条记录history. replaceState(data, title , url) ; / 替换当前页在历史记录中的这两个方法也可以改变urL页面也不会重新刷新,在当前已有的back、 forward,
8、go的基础之上,它们提供了对历史记录进行修改的功能。只是当它 们执行修改时,虽然改变了当前的URL,但浏览器不会立即向后端发送请求。.Vuex是什么?怎么使用它?哪种功能场景使用?Vuex是一个专为Vue. js应用程序开发的状态管理模式。它采用集中式存储管 理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生 变化。Vuex只能使用在vue上,因为其高度依赖于vue的双向绑定和 插件系统。 调用了 Vue. mixin,在所有组件的beforeCreate生命周期注入了设置 this. $store这样一个对象。场景有:单页应用中,组件之间的状态、音乐播放、登录状态、加入购物
9、车 state: Vuex使用单一状态树,存放的数据状态,不可以直接修改里面的数据。 mutations:定义方法动态修改Vuex的store中的状态或数据。getters:类似vue的计算属性,主耍用来过滤一些数据。actions:可以理解为通过将mutations里面处理数据的方法变成可异步的方 法,简单的说就是异步操作数据。view层通过store, dispath来分发action。modules:项目特别复杂的时候,可以让每一个模块拥有自己的state, mutation、action getters,使得结构非常清晰,方便管理。actions 和 mutations 的区别 act
10、ion主要处理的是异步的操作,mutation必须同步执行,而action既可 以处理同步,也可以处理异步的操作。action提交的是mutation,而不是直 接变更状态。如果请求来的数据不是要被其他组件公用,仅仅在请求的组件内使用,就不需 要放入vuex的state里。如果被其他地方复用,请将请求放入action里方便复用,并包装成promise 返回。.assets 和 static 的区别相同点:assets和static两个都是存放静态资源文件。项目中所需要的资 源文件图片,字体图标,样式文件等都可以放在这两个文件下。不相同点:assets中存放的静态资源文件在项目打包时,会将ass
11、ets中放置的静态资源 文件进行打包上传,所谓打包简单点可以理解为压缩体积,代码格式化。而压 缩后的静态资源文件最终也都会放置在static文件中跟着index, html 一同上 传至服务器。static中放置的静态资源文件就不会要走打包压缩格式化等流程,而是直接进 入打包好的目录,直接上传至服务器。因为避免了压缩直接进行上传,在打包 时会提高一定的效率,但是static中的资源文件由于没有进行压缩等操作, 所以文件的体积也就相对于assets中打包后的文件提交较大点。在服务器中 就会占据更大的空间。建议:将项目中template需要的样式文件js文件等都可以放置在assets中, 走打包这
12、一流程。减少体积。而项目中引入的第三方的资源文件如 iconfoont. css等文件可以放置在static中,因为这些引入的第三方文件已 经经过处理,我们不再需要处理,直接上传。Vue中key的作用是什么?需要使用key给每一个节点做唯一标识,可让diff算法可以正确识别此节点, 以更高效的更新虚拟DOMo新旧children中的节点只有顺序是不同的时候,最佳的操作应该是通过移动 元素的位置来达到更新的目的需要在新旧children的节点中保存映射关系,以便能够在旧children的节 点中找到可复用的节点。key也就是children中节点的唯一标识.用vnode描述一个D0M结构虚拟节点
13、就是用一个对象描述真实的dom元素会将template先转换成ast树,ast通过代码生成codegen转成rander 函数,rander函数内部调用$createElement方法简称_c,传入tag (创建 的元素),data(元素的属性),children(子元素).会判断children是不是一个字符串,否则会做深度递归,最后返回的结果就是一个对象,可描述出DOM 结构.简述Vue中diff算法原理1 .先同级比较,在比较子节点.2 .判断出一方有子节点另一方没有子节点的情况.如果新的一方有子节点,老的没有,则把子节点直接插入到老节点里即可. 如果老的一方有子节点,新的没有,则把老的
14、子节点直接删除.3 .判断出都有子节点的情况,递归遍历子采用双指针(头/尾指针)的方式比 对节点.Vue. use 与 Vue. component 的区别都用于注册全局组件/插件的Vue. component ()每次只能注册一个组件,功能很单一。Vponent C draggable, draggable)Vue. use()内部调用的仍是Vue. component ()去注册全局组件/插件,但它可 以做更多事情,比如多次调用Vue. component () 一次性注册多个组件,还可以 调用 Vue directive () 、 Vue. mixins () Vue. prototyp
15、e. xxx=xxx 等等, 其第 二个可选参数又可以传递一些数据Vue. use (install:function (Vue, options) / 接收传递的参数: name: My-Vue, age: 28 console.log (options, name, options.age)Vue.directive C my-directive,, inserted (el, binding, vnode) )Vue. mixin( mounted () )Vue. component( draggable5 , draggable)Vue. component ( Tree, Tree
16、) ), name: My-Vue, age: 28 )在main, js文件里动态注册全局组件时,或用到require, contextrequire, context (): 一个Webpack的API,获取一个特定的上下文(创建自 己的context),主要用来实现自动化导入模块。它会遍历文件夹中的指定文件,然后自动化导入,而不需要每次都显式使用import / require语句导入模块!在前端工程中,如果需要一个文件夹引入很多模块,则可以使用 require, context () require, context(directory, useSubdirectories = fal
17、se, regExp = 八V/)directory String)读取目录的路径useSubdirectories Boolean是否递归遍历子目录 regExp RegExp)匹配文件的正则既然Vue通过数据劫持可以精准探测数据变化,为什么还需要虚拟D0M进行 diff检测差异?现代前端框架有两种方式侦测变化,一种是pull 一种是pushpull:其代表为React,通常会用setStateAPI显式更新,然后React会进 行一层层的Virtual Dom Diff操作找出差异,然后Patch到D0M上,React 从一开始就不知道到底是哪发生了变化,只是知道有变化了,然后再进行 比较
18、暴力的Diff操作查找哪发生变化了,另外一个代表就是Angular的 脏检查操作。push: Vue的响应式系统则是push的代表,当Vue程序初始化的时候就会对 数据data进行依赖的收集,一但数据发生变化,响应式系统就会立刻得知, 因此Vue是一开始就知道是在哪发生变化了,但是这又会产生一个问题, 如果你熟悉Vue的响应式系统就知道,通常一个绑定一个数据就需要一个 Watcher , 一但我们的绑定细粒度过高就会产生大量的Watcher,这会带来内 存以及依赖追踪的开销,而细粒度过低会无法精准侦测变化,因此Vue的设计 是选择中等细粒度的方案,在组件级别进行push侦测的方式,也就是那套响
19、应 式系统,通常我们会第一时间侦测到发生变化的组件,然后在组件内部进行 Virtual Dom Diff获取更加具体的差异,而Virtual Dom Diff则是pull操 作,Vue是push+pull结合的方式进行变化侦测的。Vue为什么没有类似于React中shouldComponentUpdate的生命周期?根本原因是Vue与React的变化侦测方式有所不同React是pull的方式侦测变化,当React知道发生变化后,会使用Virtual Dom Diff进行差异检测,但是很多组件实际上是肯定不会发生变化的,这个时 候需要用shouldComponentUpdate进行手动操作来减少
20、diff,从而提高程序 整体的性能。Vue是pull+push的方式侦测变化的,在一开始就知道那个组件发生了变化, 因此在push的阶段并不需要手动控制diff,而组件内部采用的diff方式实 际上是可以引入类似于shouldComponentUpdate相关生命周期的,但是通常合 理大小的组件不会有过量的diff,手动优化的价值有限,因此目前Vue并没 有考虑引入shouldComponentUpdate这种手动优化的生命周期。.Vue中常见的性能优化1 .编码优化(1) .不要将所有的数据放在data里,data中的数据都会增加getter和 setter,收收集对应的watcher.在v
21、-for时给每项元素绑定事件必须使用时间代理(2) . SPA页面采用keep-alive缓存组件.拆分组件(提高复用性,增加代码的可维护性,减少不必要的渲染)(3) . v-if当值为false时内部指令不执行具有阻断功能,很多情况下 使用v-if代替v-show.使用key保证唯一性(4) .使用Object, freeze冻结数据,冻结后不再有getter和setter.合理使用路由懒加载和异步组件(5) .数据持久化问题如:防抖、节流2 . Vue加载性能优化.第三方模块按需导入(babel-plugin-component)(1) .滚动可视区域动态加载(vue-virtual-sc
22、rollTist / vue-virtual-scroller) 一 长列表优化(2) .图片懒加载(vue-lazyload)3 .用户体验. app-skeleton 骨架屏(1) . app-sheapp 壳4 . SEO优化. 预力口载插件 prerender-spa-plugin(1) .服务端渲染ssr5 .打包优化.使用CDN的方式加载第三方模块(1) .多线程打包. splitChunk抽离公共文件6 .缓存压缩.客户端缓存和服务端缓存(1) .服务端gzip压缩.什么是作用域插槽?1 .插槽:创建组件虚拟节点时,会将组件儿子的虚拟节点先保存起来。初 始化组件时,通过插槽属性将
23、儿子进行分类。(作用域为父组件) 渲染组件时会拿对应的slot属性的节点进行替换操作。2 .作用域插槽:在解析的时候不会作为组件的孩子节点。会解析成函数, 当子组件渲染时,会调用此函数进行渲染。(作用域为子组件) 普通插槽编译时调用createElement方法创建组件,并把子节点生成虚拟dom 做好标识存起来。渲染时调用randerSlot方法循环匹配出对应的虚拟节点在 父组件替换当前位置。而作用域插槽在编译时会把子组件编译成函数,函数不调用就不会渲染。也就 是说在初始化组件的时候并不会渲染子节点。渲染页面时调用randerSlot方 法执行子节点的函数并把对应的属性传过来。当节点渲染完成之
24、后在组件内部 替换当前位置。.Vue与Angular以及React的区别?1 .与AngularJS的区别相同点:1 .都支持指令:内置指令和自定义指令。2 .都支持过滤器:内置过滤器和自定义过滤器。3 .都支持双向数据绑定。4 .都不支持低端浏览器。不同点:1. AngularJS 采用 TypeScript 开发,而 Vue 可以使用 javascript 也可 以使用 TypeScripto2. 在性能上,AngularJS依赖对数据做脏检查,所以Watcher越多越慢。Vue. js使用基于依赖追踪的观察并且使用异步队列更新,所有的数据都 是独立触发的。对于庞大的应用来 说,这个优化差
25、异还是比较明显的。3. AngularJS社区完善,Vue的学习成本较小2.与React的区别相同点:1 . React采用特殊的JSX语法,Vue. js在组件开发中也推崇编写.vue特殊 文件格式,对文件内容都有一些约定,两者都需要编译后使用。2 .中心思想相同:一切都是组件,组件实例之间可以嵌套。3 .都提供合理的钩子函数,可以让开发者定制化地去处理需求。4 .都不内置AJAX, Route等功能核心包,而是以插件的方式加载。5 .在组件开发中都支持mixins的特性。不同点:1. vue组件分为全局注册和局部注册,在react中都是通过import相应 组件,然后模版中引用;props
26、是可以动态变化的,子组件也实时更新,在react中官方建议 props要像纯函数那样,输入输出一致对应,而且不太建议通过props 来更改视图2. vue多了指令系统,让模版可以实现更丰富的功能,而React只能使用 JSX语法react是整体的思路的就是函数式,所以推崇纯组件,数据不可变,单 向数据流,当然需要双向的地方也可以做到,比如结合redux-form,组 件的横向拆分一般是通过高阶组件。而vue是数据可变的,双向绑定, 声明式的写法,vue组件的横向拆分很多情况下用mixino3. Vue增加的语法糖computed和watch,而在React中需要自己写一套逻 辑来实现。高精度全
27、局权限处理权限控制由前端处理时,通常使用V-if / V-Show控制元素对不同权限的响应 效果。这种情况下,就会导致很多不必要的重复代码,不容易维护,因此可以 造一个小车轮,挂在全局上对权限进行处理。/注册全局自定义指令,对底层原生DOM操作Vue. directive ( permission, / inserted元素插入的时候inserted(el, binding)/获取到v-permission的值const value = bindingif (value) /根据配置的权限,去当前用户的角色权限中校验 const hasPermission = checkPermission(
28、value) if (IhasPermission) /没有权限,则移除DOM元素el. parentNode & el. parentNode. removeChild(el) else throw new Error( need key! Like v-permission=/ admin , editor5 1 )/ -在组件中使用v-permissionbutton v-permission= admin权限 l权限 2.对于vue3. 0特性你有什么了解的吗?(1) .监测机制的改变0基于代理Proxy的observer实现,提供全语言覆盖的反应性跟踪。替代 了 Vue 2采用def
29、ineProperty去定义get和set,意味着彻底放弃了兼容IE, 这也取消除了 Vue 2当中基于Object. defineProperty的实现所存在的很多限制:二只能监测属性,不能监测对象:二检测属性的添加和删除;二检测数组索引和长度的变更;二支持 Map、Set、WeakMap 和 WeakSeto新的observer还提供了以下特性:用于创建observable的公开API。这为中小规模场景提供了简单轻量级的跨 组件状态管理解决方案。默认采用惰性观察。在2.x中,不管反应式数据有多大,都会在启动时被观察 到。如果数据集很大,这可能会在应用启动时带来明显的开销。在3.x中,只 观
30、察用于渲染应用程序最初可见部分的数据。更精确的变更通知。在2.x中,通过Vue. set强制添加新属性将导致依赖于 该对象的watcher收到变更通知。在3.x中,只有依赖于特定属性的 watcher才会收到通知。不可变的observable:我们可以创建值的“不可变”版本(即使是嵌套属性), 除非系统在内部暂时将其“解禁”。这个机制可用于冻结prop传递或Vuex 状态树以外的变化。更好的调试功能:我们可以使用新的renderTracked和renderTriggered钩 子精确地跟踪组件在什么时候以及为什么重新渲染。(2) .模板模板方面没有大的变更,只改了作用域插槽,2.x的机制导致作
31、用域插槽变了, 父组件会重新渲染,而3.0把作用域插槽改成了函数的方式,这样只会影响子 组件的重新渲染,提升了渲染的性能。同时,对于render函数的方面,vue3. 0也进行一系列更改来方便习惯直接使 用api来生成vdom 。(3) .对象式的组件声明方式vue2. x中的组件是通过声明的方式传入一系列option,和TypeScript的结 合需要通过一些装饰器的方式来做,虽然能实现功能,但是比较麻烦。vue3. 0修改了组件的声明方式,改成了类式的写法,这样使得和TypeScript 的结合变得很容易。此外,vue的源码也改用了 TypeScript来写。其实当代码的功能复杂之后, 必
32、须有一个静态类型系统来做一些辅助管理。现在vue3. 0也全面改用 TypeScript来重写了,更是使得对外暴露的api更容易结合TypeScript。静 态类型系统对于复杂代码的维护确实很有必要。(4) .其它方面的更改支持自定义渲染器,从而使得weex可以通过自定义渲染器的方式来扩展,而 不是直接fork源码来改的方式。支持Fragment (多个根节点)和Protal (在dom其他部分渲染组建内容)组 件,针对一些特殊的场景做了处理。基于treeshaking优化,提供了更多的内置功能。.Vue等单页面应用(spa)及其优缺点优点:Vue的目标是通过尽可能简单的API实现响应的数据绑
33、定和组合的视图 组件,核心是一个响应的数据绑定系统。MVVM、数据驱动、组件化、轻量、简 洁、高效、快速、模块友好;即第一次就将所有的东西都加载完成,因此,不 会导致页面卡顿。缺点:不支持低版本的浏览器,最低只支持到IE9;不利于SEO的优化(如果 要支持SEO,建议通过服务端来进行渲染组件);第一次加载首页耗时相对长 一些;不可以使用浏览器的导航按钮需要自行实现前进、后退。首次页面加载会触发四个钩子函数:beforeCreate, created, beforeMount, mounted且DM0渲染在mounted中就已经完成了。可以使用$on(,hook / )或$once(hook:)
34、来简化生命周期的注册.谈谈MVVM模式Model:代表数据模型,也可以在Model中定义数据修改和操作的业务逻 辑。View:代表UI组件,它负责将 数据模型转化成UI展现出来。ViewModel:监听模型数据的改变和控制视图行为、处理用户交互,简单理解就 是一个同步View和Model的对象,连接Model和View。在MVVM架构下,View和Model之间并没有直接的联系,而是通过ViewMode 进行交互,Model和ViewModel之间的交互是双向自动的,因此View数据 的变化会同步到Model中,而Model数据的变化也会立即反应到View上。而开发者只需关注业务逻辑,不需要手
35、动操作D0M,不需要关注数据状态的同 步问题,复杂的数据状态维护完全由MVVM来统一管理。MVVM和MVC区别?mvc和mvvm其实区别并不大。都是一种设计思想。主要就是mvc中 Controller演变成mvvm中的viewModelo mvvm主要解决了 mvc中大量的 D0M操作使页面渲染性能降低,加载速度变慢,影响用户体验。和当Model频 繁发生变化,开发者需要主动更新到View o说下Vue实现数据双向绑定的原理Vue实现数据双向绑定主要是:采用数据劫持结合发布者-订阅者模式的方式, 通过Object, definePropertyO 来劫持各个属性的setter, getter,
36、在数据 变动时发布消息给订阅者,触发相应监听回调。当把一个普通Javascript对 象传给Vue实例来作为它的data选项时,Vue将遍历它的属性,用 Object, defineProperty()将它们转为 getter/settero 用户看不到 getter/setter,但是在内部它们让Vue追踪依赖,在属性被访问和修改时通 知变化。.请说一下Vue响应式数据的原理是什么?在Vue初始化数据时,使用Object. defineProperty重新定义data中所有 属性,增加了数据获取(getter) /设置(setter)的拦截功能。在获取/设 置 时可增加一些逻辑,这个逻辑交叫
37、作 依赖收集。当页面取到对应属性时会 进行依赖收集,如果属性发生变化,则会通知收集的依赖进行更新,而负责收 集的就是watchero如负责渲染的watcher会在页面渲染的时候对数据进行取值,并把当前watcher先存起来对应到数据上,当更新数据的时候告诉对应的watcher去更 新,从而实现了数据响应式。data 一般分为两大类:对象类型和数组:对象:在Vue初始化的时候,会调用initData方法初始化data,它会拿到当前用 户传入的数据。判断如果已经被观测过则不在观测,如果没有观测过则利用 new Observer创建一个实例用来观测数据。如果数据是对象类型非数组的话会 调用this,
38、 walk (value)方法把数据进行遍历,在内部使用def inReactive方 法重新定义(definReactive是比较核心的方法:定义响应式),而重新定义 采用的就是Object, defineProperty。如当前对象的值还是个对象,会自动调 用递归观测。当用户取值的时候会调用get方法并收集当前的wacther 。在 set方法里,数据变化时会调用notify方法触发数据对应的依赖进行更新。数组:使用函数劫持的方式重写了数组的方法,并进行了原型链重写。使data中的 数组指向了自己定义的数组原型方法。这样的话,当调用数组API时,可以通 知依赖更新。如果数组中包含着引用类型
39、,则会对数组中的引用类型进行再次 监控。也就是当创建了 Observer观测实例后,如果数据是数组的话,判断是否支持 自己原型链,如果不支持则调用protoAugment方法使目标指向arrayMethods 方法。arrayMethods就是重写的数组方法,包括push、pop、shift、 unshift splice sort和reverse共七个可以改变数组的方法,内部采用函 数劫持的方式。在数组调用重写的方法之后,还是会调用原数组方法去更新数 组。只不过重写的方法会通知视图更新。如果使用push、unshift和splice 等方法新增数据,会调用observeArray方法对插入的
40、数据再次进行观测。如果数组中有引用类型,则继续调用observeArray方法循环遍历每一项,继 续深度观测。前提是每一项必须是对象类型,否则observe方法会直接 returno.为何Vue采用异步渲染?如不采用异步更新,则每次更新数据都会对当前组件进行重新渲染,因此为了 性能考虑Vue在本轮数据更新结束后,再去异步更新视图。当数据变化之后,会调用notify方法去通知watcher进行数据更新。而 watcher会调用update方法进行更新(这里就是发布订阅模式)。更新时并 不是让wathcer立即执行,而是放在一个queueWatcher队列里进行过滤,相 同的watcher只存一个
41、。最后在调用nextTick方法通过flushSchedulerQueue 异步清空 watcher 队列。.nextTick实现原理?nextTick方法主要是使用了宏任务和微任务定义了一个异步方法。多次调 用nextTick会将方法存入队列中,通过这个异步方法清空当前队列。所以 nextTick方法就是异步方法。默认在内部调用nextTick时会传入flushSchedulerQueue方法,存在一个数 组里并让它执行。用户有时也会调用nextTick,调用时把用户传过来的cb也 放在数组里,都是同一个数组callbacks。多次调用nextTick只会执行一次, 等到代码都执行完毕后,会
42、调用timerFunc这个异步方法依次进行判断所支持 的类型:1 .如支持Promise则把timerFunc包裹在了 Promise中并把flushCallbacks 放在了 then 中,相当于异步执行了 flushCallBacks。 flushCallBacks函数作用就是让传过来的方法依次执行。2 .如不是 IE、支持 Mutationobserve 并且是原生的 Mutationobserveo 首先声明一个变量并创建一个文本节点。接着创建Mutationobserve实 例并把flushCallBacks传入,调用observe方法去观测每一个节点。 如果节点变化会异步执行flu
43、shCallBacks方法。3 .如果支持 setlmmediate ,则调用 setlmmediate 传入 flushCallBacks 异步执行。4 .以上都不支持就只能调用setTimeout传入flushCallBacks。作用:$nextTick是在下次D0M更新循环结束之后执行延迟回调,在修改数据 之后使用SnextTick,则可以在回调中获取更新后的D0Mo.请说一下Vue中Computed和watch ?默认computed和watch内部都是用一个watcher实现的。computed有缓存功能,不会先执行,只有当依赖的属性发生变化才会通知视图 跟新。watcher没有缓存
44、,默认会先执行,只要监听的属性发生变化就会更新视图。computed调用initComputed方法初始化计算属性时,会获取到用户定义的方法,并创 建一个watcher把用户定义传进去,这个watcher有个标识:lazy = true, 默认不会执行用户定义的函数。还有个标识dirty = true默认去求值。watcher内部调用defineComputed方法将计算属性定义在实例上,其底层也 是用的 Object, definePropertyo 并且传入了 createComputedGetter 方法定 义一个计算属性。在用户取值时,调用的是createComputedGetter返
45、I可函数 computedGettero 判断当前的 watcher, dirty 是否为 true。如果为 true 则 调用watcher, evaluate方法求值。在求值时是调用的this, get ()方法。其 实this, get ()就是用户传入的方法,执行时会把方法里的属性依次取值。而 在取值前调用了 pushTarget方法将watcher放在了全局上,当取值时会进行 依赖收集,把当前的计算属性的watcher收集起来。等数据变化则通知watcher重新执行,也就是进入到了 update方法中。update并没有直接让 watcher执行,而是将dirty二true。这样的好
46、处就是,如果dirty=true, 就进行求值,否则就返回上次计算后的值,从而实现了缓存的机制。watch调用initWatch方法初始化watch的时候,内部传入用户定义的方法调用了 createWatcher方法。在createWatcher方法中比较核心的就是$watch方法, 内部调用了 new Watcher并传入了 expOrFn和 回调函数。expOrFn如果是个 字符串的话,会包装成一个函数并返回这个字符串。这时lazy = false 了, 则直接调用了 this, get()方法取属性的值。同computed在取值前也执行 pushTarget方法将watcher放在了全局
47、上,当用户取值时就收集了 watchero 因此当属性值发生改变时,watcher就会更新。如果监听的属性值是个对象,则取对象里的值就不会更新了,因为默认只能对 属性进行依赖收集,不能对属性值是对象的进行依赖收集。想要不管属性值是 否是对象都能求值进行收集依赖,可设置deep = true。如设置了 deep = true ,则会调用traverse方法进行递归遍历。.Vue组件中data为什么必须是一个函数?因为js本身的特性带来的,同一个组件被复用多次,会创建多个实例。这些 实例是同一个构造函数。如果data是一个对象的话,那么所有组件都共享了 同一个对象。为了保证组件中数据的独立性要求每个组件必须通过data函数 返回一个对象作为组件的状态。Vue通过extend创建子类之后,会调用mergeOptions方法合并父类和子类 的选项,选中就包括datao在循环完父类和子类之后调用mergeField函数的 中的strat方法去合并data,如果data不是函数而是个对象,则会报错提 示data应该是个函数。.Vue中事件绑定原理Vue中事件绑定分为两种:1 .原生事件绑定:采用的是addEventListener实现2 .组件事件绑定:采用的是$on方法实现以click事件为例,普通Dom元素绑定事件是click
限制150内