首页 专题 文章 代码 归档

【面试】Vue的面试题汇总(个人总结)

1. vuex的作用?

vuex是一个专门为vue.js应用程序开发的状态管理模式、vuex可以帮助我们管理共享状态,也就是管理全局变量

vuex的几个核心概念:

vuex使用一个store对象管理应用的状态,一个store包括:state,getter,mutation,action四个属性

1、state: state意为'状态',是vuex状态管理的数据源

2、getter: getter的作用与filters有一些相似,可以将state进行过滤后输出

3、mutation: mutation是vuex中改变state的唯一途径,并且只能同步操作

4、action: 一些对state的异步操作可以放在action中,并通过在action提交mutaion变更状态

5、module: 当store对象过于庞大时,可以根据具体的业务需求分为多个module

2. 响应式原理

Vue 的响应式是通过 Object.defineProperty 对数据进行劫持,并结合观察者模式实现。 Vue 利用 Object.defineProperty 创建一个 observe 来劫持监听所有的属性,把这些属性全部转为 getter 和 setter。Vue 中每个组件实例都会对应一个 watcher 实例,它会在组件渲染的过程中把使用过的数据属性通过 getter 收集为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。

3. Object.defineProperty有哪些缺点?

这道题目也可以问成 “为什么vue3.0使用proxy实现响应式?” 其实都是对Object.defineProperty 和 proxy实现响应式的对比。

  1. Object.defineProperty 只能劫持对象的属性,而 Proxy 是直接代理对象
    由于 Object.defineProperty 只能对属性进行劫持,需要遍历对象的每个属性。而 Proxy 可以直接代理对象。
  2. Object.defineProperty 对新增属性需要手动进行 Observe, 由于 Object.defineProperty 劫持的是对象的属性,所以新增属性时,需要重新遍历对象,对其新增属性再使用 Object.defineProperty 进行劫持。 也正是因为这个原因,使用 Vue 给 data 中的数组或对象新增属性时,需要使用 vm.$set 才能保证新增的属性也是响应式的。
  3. Proxy 支持13种拦截操作,这是 defineProperty 所不具有的。
  4. 新标准性能红利
    Proxy 作为新标准,长远来看,JS引擎会继续优化 Proxy ,但 gettersetter 基本不会再有针对性优化。
  5. Proxy 兼容性差 目前并没有一个完整支持 Proxy 所有拦截方法的Polyfill方案

4. Vue双向绑定的原理

vue数据双向绑定是通过数据劫持结合发布者-订阅者模式的方式来实现的。具体实现过程:

我们已经知道实现数据的双向绑定,首先要对数据进行劫持监听,所以我们需要设置一个监听器Observer,用来监听所有属性。如果属性发上变化了,就需要告诉订阅者Watcher看是否需要更新。因为订阅者是有很多个,所以我们需要有一个消息订阅器Dep来专门收集这些订阅者,然后在监听器Observer和订阅者Watcher之间进行统一管理的。接着,我们还需要有一个指令解析器Compile,对每个节点元素进行扫描和解析,将相关指令对应初始化成一个订阅者Watcher,并替换模板数据或者绑定相应的函数,此时当订阅者Watcher接收到相应属性的变化,就会执行对应的更新函数,从而更新视图。因此接下去我们执行以下3个步骤,实现数据的双向绑定:

1.实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者。

2.实现一个订阅者Watcher,可以收到属性的变化通知并执行相应的函数,从而更新视图。

3.实现一个解析器Compile,可以扫描和解析每个节点的相关指令,并根据初始化模板数据以及初始化相应的订阅器。

流程图如下:

截图-1598343232

5. axios的作用?

一句话: vue中的ajax,用于向后台发起请求

特点:

  • 从浏览器中创建XMLHttpRequests
  • 从node.js创建http请求
  • 支持Promise API
  • 拦截请求和响应
  • 转换请求数据和响应数据
  • 取消请求
  • 自动转换json数据
  • 客户端支持防御XSRF

promise:

一个对象用来传递异步操作的信息

promise的出现主要是解决地狱回调的问题,无需多次嵌套

本质:分离异步数据获取和业务

拦截器:

请求拦截器

axios.interceptors.request.use(function(config){
    return config;
},function(error){
    return Promise.reject(error);
});

响应拦截器

axios.interceptors.response.use(function(response){
    return response;
},function(error){
    return Promise.reject(error);
});

在响应拦截器中也可以做很多事情,比如前后端分离中,检测到后端如果响应验证失败,或身份已过期,那么在这里就可以统一返回到登录界面。

6. 列举Http请求中常见的请求方式?

get

  • 向特定的路径资源发出请求,数据暴露在url中

post

  • 向指定路径资源提交数据进行处理请求,数据包含在请求体中

options

  • 返回服务器针对特定资源所支持的http请求方法,允许客户端查看,测试服务器性能

head

  • 向服务器与get请求相一致的响应,响应体不会返回,可以不必传输整个响应内容

put

  • 从客户端向服务器端传送的数据取代指定的文档的内容

delete

  • 请求服务器删除指定的页面

trace

  • 回显服务器收到的请求,主要用于测试或者诊断

connect

  • http/1.1协议中预留给能够将连接改为管道方式的代理服务

7. 对于MVVM的理解?

MVVM 是 Model-View-ViewModel 的缩写。

Model代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑。

View 代表UI 组件,它负责将数据模型转化成UI 展现出来。

ViewModel 监听模型数据的改变和控制视图行为、处理用户交互,简单理解就是一个同步View 和 Model的对象,连接Model和View。

viewmodel和model实现双向数据绑定

8. Vue的生命周期?

1、什么是vue生命周期?

答: Vue 实例从创建到销毁的过程,就是生命周期。从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、销毁等一系列过程,称之为 Vue 的生命周期。

2、vue生命周期的作用是什么?

答:它的生命周期中有多个事件钩子,让我们在控制整个Vue实例的过程时更容易形成好的逻辑。

3、vue生命周期总共有几个阶段?

答:它可以总共分为8个阶段:创建前/后, 载入前/后,更新前/后,销毁前/销毁后。

4、第一次页面加载会触发哪几个钩子?

答:会触发 下面这几个beforeCreate, created, beforeMount, mounted 。

5、DOM 渲染在 哪个周期中就已经完成?

答:DOM 渲染在 mounted 中就已经完成了。

9. 简述每个周期具体适合哪些场景

1、beforeCreate:在new一个vue实例后,只有一些默认的生命周期钩子和默认事件,其他的东西都还没创建。在beforeCreate生命周期执行的时候,data和methods中的数据都还没有初始化。不能在这个阶段使用data中的数据和methods中的方法

2、created:data 和 methods都已经被初始化好了,如果要调用 methods 中的方法,或者操作 data 中的数据,最早可以在这个阶段中操作

3、beforeMount:执行到这个钩子的时候,在内存中已经编译好了模板了,但是还没有挂载到页面中,此时,页面还是旧的

4、mounted:执行到这个钩子的时候,就表示Vue实例已经初始化完成了。此时组件脱离了创建阶段,进入到了运行阶段。 如果我们想要通过插件操作页面上的DOM节点,最早可以在和这个阶段中进行

5、beforeUpdate: 当执行这个钩子时,页面中的显示的数据还是旧的,data中的数据是更新后的, 页面还没有和最新的数据保持同步

6、updated:页面显示的数据和data中的数据已经保持同步了,都是最新的

7、beforeDestory:Vue实例从运行阶段进入到了销毁阶段,这个时候上所有的 data 和 methods , 指令, 过滤器 ……都是处于可用状态。还没有真正被销毁

8、destroyed: 这个时候上所有的 data 和 methods , 指令, 过滤器 ……都是处于不可用状态。组件已经被销毁了。

10. created和mounted的区别

created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。 mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作

11. Vue实现数据双向绑定的原理?

采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应监听回调。

12. Vue组件间的参数传递?

1、父组件与子组件传值

父组件传给子组件:子组件通过props方法接受数据;

子组件传给父组件:$emit方法传递参数

2、非父子组件间的数据传递,兄弟组件传值

eventBus,就是创建一个事件中心,相当于中转站,可以用它来传递事件和接收事件。项目比较小时,用这个比较合适。(虽然也有不少人推荐直接用VUEX,具体来说看需求咯。技术只是手段,目的达到才是王道。)

具体的说,就是再创建一个单独的Vue实例,然后在其他需要传值、接收值的组件中,导入这个Vue实例,通过$emit和$on传值和接收值。

13. Vue的路由实现?

hash模式 和 history模式

1、hash模式:在浏览器中符号“#”,#以及#后面的字符称之为hash,用window.location.hash读取;

特点:hash虽然在URL中,但不被包括在HTTP请求中;用来指导浏览器动作,对服务端安全无用,hash不会重加载页面。

hash 模式下,仅 hash 符号之前的内容会被包含在请求中,如 http://www.xxx.com,因此对于后端来说,即使没有做到对路由的全覆盖,也不会返回 404 错误。

2、history模式:history采用HTML5的新特性;且提供了两个新方法:pushState(),replaceState()可以对浏览器历史记录栈进行修改,以及popState事件的监听到状态变更。

对于个人来说,更喜欢history模式,此模式看着顺眼一些,但是需要在后端服务器(Nginx、Apache)中配置伪静态规则,不然会报404错误

配置也不难,几行代码(如下是Nginx规则):

location / {
  try_files $uri $uri/ /index.html;
}

14. vue路由的钩子函数?

首页可以控制导航跳转,beforeEach,afterEach等,一般用于页面title的修改。一些需要登录才能调整页面的重定向功能。

beforeEach主要有3个参数to,from,next:

to:route即将进入的目标路由对象,

from:route当前导航正要离开的路由

next:function一定要调用该方法resolve这个钩子。执行效果依赖next方法的调用参数。可以控制网页的跳转。

如果验证通过,一定要执行next中间件,不然是页面时无法跳转的!

15. $route 和 $router 的区别

1、$router是VueRouter的实例,在script标签中想要导航到不同的URL,使用$router.push方法。返回上一个历史history用$router.to(-1)

2、$route为当前router跳转对象。里面可以获取当前路由的name,path,query,parmas等。

16. vue新增自定义指令?

// 1.创建局部指令

var app = new Vue({
    el: '#app',
    data: {    
    },
    // 创建指令(可以多个)
    directives: {
        // 指令名称
        dir1: {
            inserted(el) {
                // 指令中第一个参数是当前使用指令的DOM
                console.log(el);
                console.log(arguments);
                // 对DOM进行操作
                el.style.width = '200px';
                el.style.height = '200px';
                el.style.background = '#000';
            }
        }
    }
})

// 2.全局指令

Vue.directive('dir2', {
    inserted(el) {
        console.log(el);
    }
})

// 3.指令的使用

<div id="app">
    <div v-dir1></div>
    <div v-dir2></div>
</div>

17. vue如何自定义一个过滤器?

//html代码:

<div id="app">
     <input type="text" v-model="msg" />
     {{msg| capitalize }}
</div>

//JS代码:

var vm=new Vue({
    el:"#app",
    data:{
        msg:''
    },
    filters: {
      capitalize: function (value) {
        if (!value) return ''
        value = value.toString()
        return value.charAt(0).toUpperCase() + value.slice(1)
      }
    }
})

全局定义过滤器

Vue.filter('capitalize', function (value) {
  if (!value) return ''
  value = value.toString()
  return value.charAt(0).toUpperCase() + value.slice(1)
})

// 过滤器接收表达式的值 (msg) 作为第一个参数。capitalize 过滤器将会收到 msg的值作为第一个参数。

18. 对keep-alive 的了解?

keep-alive是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。 在vue 2.1.0 版本之后,keep-alive新加入了两个属性: include(包含的组件缓存) 与 exclude(排除的组件不缓存,优先级大于include) 。

使用方法

<keep-alive include='include_components' exclude='exclude_components'>
  <component>
    <!-- 该组件是否缓存取决于include和exclude属性 -->
  </component>
</keep-alive>

参数解释

  • include - 字符串或正则表达式,只有名称匹配的组件会被缓存
  • exclude - 字符串或正则表达式,任何名称匹配的组件都不会被缓存
  • include 和 exclude 的属性允许组件有条件地缓存。二者都可以用“,”分隔字符串、正则表达式、数组。当使用正则或者是数组时,要记得使用v-bind 。

使用示例

<!-- 逗号分隔字符串,只有组件a与b被缓存。 -->
<keep-alive include="a,b">
  <component></component>
</keep-alive>

<!-- 正则表达式 (需要使用 v-bind,符合匹配规则的都会被缓存) -->
<keep-alive :include="/a|b/">
  <component></component>
</keep-alive>

<!-- Array (需要使用 v-bind,被包含的都会被缓存) -->
<keep-alive :include="['a', 'b']">
  <component></component>
</keep-alive>

19. v-if 和 v-show 区别?

v-if按照条件是否渲染,v-show是display的block或none;

值得一说的是,Vue是不建议(不允许)在v-for中使用v-if,只能使用v-show

20. vue.js的两个核心是什么?

数据驱动、组件系统

21. vue常用的修饰符?

  • .prevent: 提交事件不再重载页面;
  • .stop: 阻止单击事件冒泡;
  • .self: 当事件发生在该元素本身而不是子元素的时候会触发;
  • .capture: 事件侦听,事件发生的时候会调用

22. vue中 key 值的作用?

当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用“就地复用”策略。

如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。key的作用主要是为了高效的更新虚拟DOM。

23. vue几种常用的指令?

v-for 、 v-if 、v-bind、v-on、v-show、v-else

24. 定义动态路由? 获取传过来的值

在 router 目录下的 index.js 文件中,对 path 属性加上/:id,使用 router 对象的 params.id 获取。

25. v-on可以监听多个方法吗?

可以,栗子:

<input type="text" v-on="{ input:onInput,focus:onFocus,blur:onBlur, }">

26. vue组件中data为什么必须是一个函数?

因为JavaScript的特性所导致,在component中,data必须以函数的形式存在,不可以是对象。

组建中的data写成一个函数,数据以函数返回值的形式定义,这样每次复用组件的时候,都会返回一份新的data,相当于每个组件实例都有自己私有的数据空间,它们只负责各自维护的数据,不会造成混乱。而单纯的写成对象形式,就是所有的组件实例共用了一个data,这样改一个全都改了。

27. 单页面应用和多页面应用区别及优缺点?

1、单页面应用(SPA),通俗一点说就是指只有一个主页面的应用,浏览器一开始要加载所有必须的 html, js, css。所有的页面内容都包含在这个所谓的主页面中。但在写的时候,还是会分开写(页面片段),然后在交互的时候由路由程序动态载入,单页面的页面跳转,仅刷新局部资源。多应用于pc端。

2、多页面(MPA),就是指一个应用中有多个页面,页面跳转时是整页刷新

单页面的优点:

用户体验好,快,内容的改变不需要重新加载整个页面,基于这一点spa对服务器压力较小;前后端分离;页面效果会比较炫酷(比如切换页面内容时的专场动画)。

单页面缺点:

不利于seo;导航不可用,如果一定要导航需要自行实现前进、后退。(由于是单页面不能用浏览器的前进后退功能,所以需要自己建立堆栈管理);初次加载时耗时多;页面复杂度提高很多。

28. vue初始化页面闪动问题

使用vue开发时,在vue初始化之前,由于div是不归vue管的,所以我们写的代码在还没有解析的情况下会容易出现花屏现象,看到类似于{{message}}的字样,虽然一般情况下这个时间很短暂,但是我们还是有必要让解决这个问题的。

两个解决办法:

1、根元素加入:style="display: none;"

2、在需要类似{{message}}的地方,加个span,然后就尽量使用v-text

29. 父组件子组件生命周期执行顺序

加载过程:

父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted

子组件更新过程:

父beforeUpdate->子beforeUpdate->子updated->父updated

父组件更新过程:

父beforeUpdate->父updated

销毁过程:

父beforeDestroy->子beforeDestroy->子destroyed->父destroyed

30. Vue深度监听

原理:

默认情况下 handler 只监听obj这个属性它的引用的变化,我们只有给obj赋值的时候它才会监听到

deep的意思就是深入观察,监听器会一层层的往下遍历,给对象的所有属性都加上这个监听器,但是这样性能开销就会非常大了,任何修改obj里面任何一个属性都会触发这个监听器里的 handler。

31. Watch和Computed的区别

1、从属性名上,computed是计算属性,也就是依赖其它的属性计算所得出最后的值。watch是去监听一个值的变化,然后执行相对应的函数

2、从实现上,computed的值在 getter执行后是会缓存的,只有在它依赖的属性值改变之后,下一次获取computed的值时才会重新调用对应的 getter来计算。watch在每次监听的值变化时,都会执行回调。其实从这一点来看,都是在依赖的值变化之后,去执行回调。很多功能本来就很多属性都可以用,只不过有更适合的。如果一个值依赖多个属性(多对—),用 Computed肯定是更加方便的。如果一个值变化后会引起一系列操作,或者一个值变化会引起一系列值的变化(一对多),用 watch更加方便一些。

3、watch的回调里面会传入监听属性的新旧值,通过这两个值可以做一些特定的操作。computed通常就是简单的计算

4、watch和 computed并没有哪个更底层,watch内部调用的是vm.$watch,它们的共同之处就是每个定义的属性都单独建立了一个 Watcher对象。

32. v-if和v-for

由于v-for的优先级比v-if高,所以导致每循环一次就会去v-if一次,而v-if是通过创建和销毁dom元素来控制元素的显示与隐藏,所以就会不停的去创建和销毁元素,造成页面卡顿,性能下降。

解决办法:在v-for的外层或内层包裹一个元素来使用v-if

33. watch能监听到数组的pop行为

对于有返回值的数据,watch就能监听到,比如数组的pop,push, unshift,map等行为。

34. JS中的内存泄漏问题

定义:程序不需要的内存,由于某些原因其不会返回到操作系统或者可用内存池中。内存泄露会导致(运行缓慢 ,高延迟,崩溃)的问题,常见的导致内存泄露的原因有:

  • 意外的全局变量
  • 被遗忘的计时器或回调函数
  • 脱离文档的DOM的引用
  • 闭包

35. 跨域问题

由于浏览器的同源策略会导致跨域,同源策略又分为

  • DOM同源策略:禁止对不同源页面的DOM进行操作,主要是不同域名的ifram是限制互相访问的
  • xmlHttpRequest同源策略:禁止使用XHR对象向不同源的服务器地址发起http请求,只要 "协议:域名:端口" 有一个不同都被当做不同的域之间的请求,即跨域请求

解决方式:

  • CORS跨域资源共享 后端需要设置Access--Control-Allow-Credentials:true
  • jsonp实现跨域:动态创建script,利用src属性进行跨域
  • nginx代理跨域
  • nodejs中间件代理跨域
  • WebSokect协跨域
  • window.name+ifram跨域

36. Vue的子组件为什么不能更改父组件prop

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

此文阅读完毕,您可以:分享
二维码图片 扫描关注我们哟