Vue-前端面试题-学习自用

207 阅读12分钟
1. vue响应式原理是什么?

vue在初始化数据时,会使用Object.defineProperty重新定义data中的所有属性,当页面使用对应属性时,会首先进行依赖收集,如果属性发生变化则通知相关依赖进行更新操作。

2. 谈一谈对MVVM的理解?

model-view-viewModel,model是数据模型,view是ui组件,viewModel是沟通model和view之间的桥梁,数据会绑定到viewModel并自动更新视图,视图发生变化时也会通知viewModel更新数据。

优点:分离视图和模型,降低代码耦合。

缺点:视图状态多,维护成本高。

3. computed和watch的区别

computed:

(1)支持缓存,只有依赖的数据发生了变化,才会重新计算。

(2)不支持异步,如果computed中有异步操作时,无法监听数据变化。

(3)当computed中属性值是函数时,会默认使用get方法,函数的返回值是属性的属性值。当数据发生变化时,会使用set方法。

watch:

(1)不支持缓存,数据发生变化时,就会执行相应的操作。

(2)支持异步。

(3)函数接收两个参数,一个是变化后的新数据,一个是变化之前的旧数据。

(4)监听的属性必须是data中声明的变量或父组件传递到props中的数据。

(5)函数有两个参数:

immediate:立即执行。

deep:深度监听,在复杂数据类型中使用。

运用场景:

当需要进行数值计算,并且依赖于其他数据时,应该使用computed,可以利用computed的缓存特性,避免多次重新计算。

当需要执行异步或开销较大的操作时,应该使用watch。

4. computed和methods的区别

computed是基于它们的依赖执行的,只有依赖繁盛变化时才会更新数据。

methods只要调用就会进行更新操作。

5. slot是什么?有什么作用?原理是什么?

slot是vue的内容分发机制,分为默认插槽(匿名插槽)、具名插槽、作用域插槽。

默认插槽(匿名插槽):没有name属性,一个组件内只有一个默认插槽。

具名插槽:有name属性,一个组件内可以有多个具名插槽。

作用域插槽:是默认插槽、具名插槽的变体,在子组件渲染作用域插槽时,可以将子组件内部的数据传递给父组件,父组件根据这些数据决定如何渲染子组件。

6. 过滤器的作用,如何实现一个过滤器?

过滤器是用来过滤数据的,可以将数据格式化展示,它不会修改数据,只是改变用户看到的输出。

过滤器是一个函数,它会把表达式中的值始终当作函数的第一个参数。

7. 常见的事件修饰符及其作用?

.stop:防止事件冒泡。

.prevent:阻止预设行为发生。

.capture:事件捕获,与stop相反。

.self:只触发自己范围内的事件,不包含子元素。

.once:只触发一次。

8. v-if、v-show的原理和区别?

原理:

v-if会调用addIfCondation方法,在生成vnode的时候忽略掉相对应节点,render的时候就不会渲染。

v-show生成vnode的时候会生成响应节点,在render时会修改相关节点的display属性。

区别:

(1)v-if是动态的向dom树内添加或删除dom元素;v-show是通过设置dom元素的display样式属性控制显隐。

(2)v-if切换有个局部编译/卸载的过程;v-show只是简单的基于css的切换。

(3)v-if只有在条件第一次变为真时才开始局部编译;v-show是在任何条件下都被编译。

(4)v-if有更高的切换消耗;v-show有更高的初始渲染消耗。

(5)v-if不适合频繁切换;v-show适合频繁切换。

9. v-model实现原理?

使用v-bind将表单元素值与数据进行双向绑定,当数据发生变化时,会触发input事件,并将最新的数据传递给绑定的数据。

10. data为什么是一个函数而不是对象?

因为Vue的组件在不同的实例之间是共享的。如果直接使用对象定义data,那么所有的组件实例都会共享同一个data对象,这样在修改data属性时会同时影响到所有的组件实例,造成数据混乱和意料之外的结果。

11. 对keep-alive的理解,它是如何实现的,具体缓存的是什么?

如果需要在组件切换时,保存一些组件的状态防止多次渲染,就可以使用keep-alive包裹需要保存的组件。

keep-alive有以下三个属性:

(1)include字符串或正则表达式,只有名称匹配的组件会被匹配。

(2)exclude字符串或正则表达式,任何明正匹配的组件都不会被匹配。

(3)max数字,最多可以缓存多少组件示例。

12. $nextTick原理及作用?

在下次DOM更新循环结束之后执行延迟回调,nextTick主要使用了宏任务和微任务,根据执行环境分别尝试采用:promise、mutationObserver、setImmediate,如果以上都不行则采用setTimeOut。

13. vue中封装的数组方法有哪些,其如何实现页面更新?

push()、pop()、shift()、unshift()、splice()、sort()、reverse()

使用了函数劫持的方式,重写了数组的方法,vue将data中的数组进行了原型链重写,指向了自己定义的数组原型方法。这样当调用数组api时,可以通知依赖更新。如果数组中包含着引用类型,会对数组中的引用类型再次递归遍历进行监控。

14. 描述下vue自定义指令?

使用场景:一般需要对dom元素进行底层操作时使用。

(1)自定义指令基本内容

  • 全局定义:Vue.deriective("focus",{})

  • 局部定义:directives:{focus:{}}

  • 钩子函数:指令定义对象提供钩子函数。

    • bind:只调用一次,指令第一次绑定到元素时调用。
    • inSerted:被绑定元素插入父节点时调用(仅保证父节点存在,但不一定已被插入文档中。)
    • updated:所在组件的VNode更新时调用。
    • ComponentVNode:指令所在组件的VNode及其子VNode全部更新后调用。
    • unbind:只调用一次,指令与元素解绑时调用。
  • 钩子函数参数

    • el:绑定元素。
    • bing:指令核心对象,描述指令全部信息属性。
    • vnode:虚拟节点。
    • oldVnode:上一个虚拟节点。

(2)使用案例

初级应用:鼠标聚焦、下拉菜单

高级使用:自定义指令实现图片懒加载、自定义指令集成第三方插件

15. 子组件可以直接改变父组件的数据吗?

不能,父子组件之间是单向数据流。

每次父级组件数据更新时,子组件prop都将会刷新为最新的值。

如果这样操作,浏览器会发出警告。

Vue提倡单向数据流,即父级组件的props更新会流向子组件,反过来则不行。这样是为了防止意外的改变父组件的数据,导致数据流混乱。

只能通过$emit派发一个事件,父组件接收到后,由父组件更改数据。

16. 对Vue和React的理解,它们的异同?

相似之处:

都将注意力集中在核心库,而其他功能如路由和全局状态管理在其他库。

都有自己的构建工具,可以快速得到一个经过最佳实践的模板。

都使用虚拟dom提高重绘性能。

都有props,支持组件之间数据传递。

都提倡组件化,提高代码可复用性。

不同之处:

vue支持双向数据绑定,react提倡单向数据流。

vue鼓励写近似常规的html模板,react提倡使用jsx。

17. vue的优点

轻量级框架,只关注视图层。

双向数据绑定,操作更简便。

组件化,代码可复用性高。

虚拟dom,节省性能。

18. assets和static区别?

assets和static都是存放静态资源文件的。

assets中的文件会在项目进行打包时一起打包,也就是压缩文件和代码格式化,static中的文件不会进行压缩。所以通常使用assets的项目文件打包后体积较小。

19. delete和Vue.delete删除数组的区别?

delete只是改变了指定元素的键值为empty/undefined,其他元素的键值没变。

Vue.delete改变了整个数组的键值。

20. 什么是mixin?

mixin使我们能为vue组件编写可拔插可重用的组件功能。

21. 对SSR的理解?

SSR也就是服务器端渲染,也就是把vue在客户端将标签渲染成HTML的工作放在服务器端去做,再把HTML返回给客户端。

优点:

首屏加载速度更快。

更好的SEO

缺点:

开发条件会受到限制,服务器端渲染只支持beforeCreate和created两个钩子。

22. Vue性能优化有哪些?

尽量减少data中的数据。

v-if和v-for不能同时使用。

如果需要给v-for中的每一项绑定事件,使用事件代理。

根据实际情况分别使用v-if和v-show

SPA页面采用keep-alive缓存组件。

防抖、节流

SSR

23. 对SPA单页面的理解,它的优缺点分别是什么?

仅在页面初始化时加载相应的HTML、JavaScript、css,一旦页面加载完成,SPA不会因为用户的操作而进行页面的重新加载和跳转,而是利用路由机制实现HTML内容的变换。

24. v-if和v-for哪个优先级更高?如果同时出现,应该如何优化?

v-for优先于v-if被解析。

可以在外层嵌套template,在这一层进行if判断。

25. Vue的生命周期?

beforeCreate是new Vue()之后触发的第一个钩子,在当前阶段data、computed、methods、watch上的数据和方法都不能被访问。

created:在实例创建完成后发生,此时已经完成了数据观测,可以使用及更改数据。在这个阶段更改数据不会触发updated。当前阶段不能与dom交互,如果非要访问,可以使用vm.$nextTick。

beforeMount:发生在挂载之前,在当前阶段虚拟dom已经创建完成,即将开始渲染。在此时可以对数据进行更改,不会触发updated。

mounted:在挂载完成之后发生,此时真实的dom已经挂载完毕,完成双向数据绑定,在此阶段可以访问到dom,使用$refs对dom进行操作。

beforeUpdate:响应式数据发生更新,虚拟dom重新渲染之前被触发。当前阶段可以更改数据,不会造成updated重渲染。

updated:发生在更新完成之后,当前阶段组件dom已经完成更新。此时不可以更改数据,可能会导致无限循环。

beforeDestory:发生在销毁之前,此时可以进行收尾工作。如清除定时器。

destoryed:发生在实例销毁之后,此时只剩一个空dom。

(另外还有keep-alive独有的生命周期:activated和deactivated。用keep-alive包裹的组件在切换时不会进行销毁,而是缓存到内存中并执行deactivated钩子函数,命中缓存渲染后会执行activated钩子函数。)

26. vue子组件和父组件执行顺序

加载渲染过程

父组件:beforeCreate

父组件:created

父组件:beforeMount

子组件:beforeCreate

子组件:created

子组件:beforeMount

子组件:mounted

父组件:mounted

更新过程

父组件:beforeUpdate

子组件:beforeUpdate

子组件:updated

父组件:updated

销毁过程:

父组件:beforeDestory

子组件:beforeDestory

子组件:destoryed

父组件:destoryed

27. 组件通信?

(1)父子组件间通信

  • 子组件通过 props 属性来接受父组件的数据,然后父组件在子组件上注册监听事件,子组件通过 emit 触发事件来向父组件发送数据。
  • 通过 ref 属性给子组件设置一个名字。父组件通过 $refs 组件名来获得子组件,子组件通过 $parent 获得父组件,这样也可以实现通信。
  • 使用 provide/inject,在父组件中通过 provide提供变量,在子组件中通过 inject 来将变量注入到组件中。不论子组件有多深,只要调用了 inject 那么就可以注入 provide中的数据。

(2)兄弟组件间通信

  • 使用 eventBus 的方法,它的本质是通过创建一个空的 Vue 实例来作为消息传递的对象,通信的组件引入这个实例,通信的组件通过在这个实例上监听和触发事件,来实现消息的传递。
  • 通过 $parent/$refs 来获取到兄弟组件,也可以进行通信。

(3)任意组件之间

  • 使用 eventBus ,其实就是创建一个事件中心,相当于中转站,可以用它来传递事件和接收事件。
28. 路由懒加载如何实现?

(1)使用箭头函数+import动态加载

(2)使用箭头函数+require动态加载

29. 路由的hash和history模式

默认的路由模式是hash模式。

(1)hash模式:

URL中带着一个#,hash值会出现在URL里,但不会出现在HTTP请求中,对后端完全没影响,所以改变hash值,不会重新加载页面。

(2)history模式:

history模式中URL没有#,使用的是传统的路由分发模式,即用户在输入一个URL时,服务器会接收这个请求。

30. routeroute和router的区别?

$route是路由信息对象,包括path、params、hash、query等路由信息参数。

$router是路由实例对象,包括了路由的跳转方法,钩子函数等。

31. vue-router跳转和location.href有什么区别?

location.href简单方便,但刷新了页面。

router.push实现了按需加载,减少了dom的消耗。

32. params和query有什么区别?

query要用path来引入,params要用name来引入。

query在浏览器显示参数,params不显示。

query刷新不会丢失数据,params刷新会丢失数据。

33. vue-router导航守卫有哪些?

全局前置/钩子:beforeEach、beforeResolve、afterEach

路由独享守卫:beforeEnter

组件内守卫:beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave

34. vuex和localStorage的区别?

vuex存储在内存中。localStorage以文件形式存储在本地,只能是字符串。

刷新页面时vuex会丢失,localStorage不会丢失。

35. Redux 和 Vuex 有什么区别,它们的共同思想

(1)Redux 和 Vuex区别

  • Vuex改进了Redux中的Action和Reducer函数,以mutations变化函数取代Reducer,无需switch,只需在对应的mutation函数里改变state值即可
  • Vuex由于Vue自动重新渲染的特性,无需订阅重新渲染函数,只要生成新的State即可
  • Vuex数据流的顺序是∶View调用store.commit提交对应的请求到Store中对应的mutation函数->store改变(vue检测到数据变化自动渲染)

通俗点理解就是,vuex 弱化 dispatch,通过commit进行 store状态的一次更变;取消了action概念,不必传入特定的 action形式进行指定变更;弱化reducer,基于commit参数直接对数据进行转变,使得框架更加简易;

(2)共同思想

  • 单—的数据源
  • 变化可以预测

本质上:redux与vuex都是对mvvm思想的服务,将数据从视图中抽离的一种方案;

形式上:vuex借鉴了redux,将store作为全局的数据中心,进行mode管理;

36. 为什么要用 Vuex 或者 Redux

由于传参的方法对于多层嵌套的组件将会非常繁琐,并且对于兄弟组件间的状态传递无能为力。我们经常会采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝。以上的这些模式非常脆弱,通常会导致代码无法维护。

所以需要把组件的共享状态抽取出来,以一个全局单例模式管理。在这种模式下,组件树构成了一个巨大的"视图",不管在树的哪个位置,任何组件都能获取状态或者触发行为。

另外,通过定义和隔离状态管理中的各种概念并强制遵守一定的规则,代码将会变得更结构化且易维护。

37. Vuex有哪几种属性?

有五种,分别是 State、 Getter、Mutation 、Action、 Module

  • state => 基本数据(数据源存放地)
  • getters => 从基本数据派生出来的数据
  • mutations => 提交更改数据的方法,同步
  • actions => 像一个装饰器,包裹mutations,使之可以异步。
  • modules => 模块化Vuex