vue 前端面试题(个人面试经历,吐血整理)

都是本人面试过程中所经历过得问题,然后不断积累,整理如下,希望能帮到正在找工作的你,good luck

vue的两个核心

vue实现数据双向绑定主要是:采用 数据劫持结合发布者-订阅者模式 的方式,通过 Object.defineProperty() 来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应监听回掉。当把一个普通 JavaScript 对象传给Vue 实例来作为它的 data 选项时,Vue 将遍历它的属性,用Object.defineProperty 将他们转为 getter/setter。用户看不到getter / setter ,但是在内部它们让vue追踪依赖,在属性被访问和修改时通知变化。

vue的数据双向绑定 将MVVM作为数据绑定的入口,整合Observer,Complie 和 Watcher三者,通过Observer来监听自己的model的数据变化,通过Complie来解析编译模板指令(vue中是用来解析 {{ }} ),最终利用watcher搭起observer和complie之间的通信桥梁,达到数据变化 ==》 视图更新,视图交互变化(input)==》 数据model变更双向绑定效果。

实现步骤:

1.实现一个监听者Oberver来劫持并监听所有的属性,一旦有属性发生变化就通知订阅者

2.实现一个订阅者watcher来接受属性变化的通知并执行相应的方法,从而更新视图

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

第一步:需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter和getter

这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化

第二步:compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图

第三步:Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是:

1、在自身实例化时往属性订阅器(dep)里面添加自己

2、自身必须有一个update()方法

3、待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。

第四步:MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。

 

1、数据驱动,也叫双向数据绑定

vue.js数据观察原理在技术实现上,利用的是ES5的object.defineproperty和存储器属性:getter和setter(只兼容IE9以上的版本),可称为基准依赖收集的观测模式。核心是VM,即ViewModel,保证数据和视图的一致性。

观察者模式:发布-订阅

2、组件系统。

vue组件的核心选项:

模板、初始数据、接受的外部参数、方法、生命周期的钩子函数、私有资源

 

Vue.set() 响应式新增与修改数据

什么情况下使用$set?

由于 Vue 会在初始化实例时进行双向数据绑定,使用Object.defineProperty()对属性遍历添加 getter/setter 方法,所以属性必须在 data 对象上存在时才能进行上述过程 ,这样才能让它是响应的。如果要给对象添加新的属性,此时新属性没有进行过上述过程,不是响应式的,所以会出想数据变化,页面不变的情况。此时需要用到$set。

向响应式对象中添加一个属性,并确保这个新属性同样是响应式的,且触发视图更新。它必须用于向响应式对象上添加新属性,因为 Vue 无法探测普通的新增属性

(比如 this.myObject.newProperty = 'hi')(官方示例) 我自己的理解就是,在vue中对一个对象内部进行一些修改时,vue没有监听到变化无法触发视图的更新,此时来使用$set来触发更新,使视图更新为最新的数据。

由于 JavaScript 的限制,Vue 不能检测以下数组的变动:

  1. 当你利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue
  2. 当你修改数组的长度时,例如:vm.items.length = newLength

 

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>

 

 

vue请求数据放在created好还是mounted里好

建议放在created里

created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。

mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作。

如果在mounted钩子函数中请求数据可能导致页面闪屏问题

其实就是加载时机问题,放在created里会比mounted触发早一点,如果在页面挂载完之前请求完成的话就不会看到闪屏了

 

vue组件中data为什么必须是函数

因为一个组件是可以共享的,但他们的data是私有的,所以每个组件都要return一个新的data对象,返回一个唯一的对象。

 

hash和history两种模式的区别

  • hash —— 即地址栏 URL 中的 # 符号(此 hash 不是密码学里的散列运算)。比如这个 URL:http://www.abc.com/#/hello,hash 的值为 #/hello。它的特点在于:hash 虽然出现在 URL 中,但不会被包括在 HTTP 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。
  • hash 模式下,仅 hash 符号之前的内容会被包含在请求中,如 http://www.abc.com,因此对于后端来说,即使没有做到对路由的全覆盖,也不会返回 404 错误。
  • history —— 利用了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 方法。(需要特定浏览器支持)这两个方法应用于浏览器的历史记录栈,在当前已有的 back、forward、go 的基础之上,它们提供了对历史记录进行修改的功能。只是当它们执行修改时,虽然改变了当前的 URL,但浏览器不会立即向后端发送请求。
  • history 模式下,前端的 URL 必须和实际向后端发起请求的 URL 一致,如 http://www.abc.com/book/id。如果后端缺少对 /book/id 的路由处理,将返回 404 错误。 Vue-Router 官网里如此描述:“不过这种模式要玩好,还需要后台配置支持……所以呢,你要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。”

 

 

路由传参的几种方式

一、通过调用$router对象的push()方法,向push()方法传递一个路由配置对象,通过params来传递参数

需要注意的是使用params必须和name属性一起使用,否则要跳转的目标路由页面无法通过params获取到传递过来的参数。

this.$route.params.userName;//User.vue组件中就可以通过$route的params获取到

二、通过调用$router对象的push()方法,向push()方法传递一个路由配置对象,需要通过query来传递参数

需要注意的是使用query的时候,可以通过path属性也可以通过name属性来指定目标路由。

这种情况下,query传递的参数会显示在url后面?userName=?&,如:

http://localhost:8082/about?userName=lhb

三、通过路由配置,配置动态路由参数

this.$router.push({path:`/user/${userName}`});

 

指令v-el的作用是什么?

提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标.可以是 CSS 选择器,也可以是一个 HTMLElement 实例,

 

为什么在vue中使用axios

1.axios:

  • 从 node.js 创建 http 请求
  • 支持 Promise API
  • 客户端支持防止CSRF
  • 提供了一些并发请求的接口(重要,方便了很多的操作)

2.jQuery ajax:

  • 本身是针对MVC的编程,不符合现在前端MVVM
  • 基于原生的XHR开发,XHR本身的架构不清晰,已经有了fetch的替代方案
  • JQuery整个项目太大,单纯使用ajax却要引入整个JQuery非常的不合理(采取个性化打包的方案又不能享受CDN服务)

 

vue中nextTick的作用

$nextTick 是在下次 DOM 更新循环结束之后执行延迟回调,在修改数据之后使用 $nextTick,则可以在回调中获取更新后的 DOM

在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。(官网解释)

解决的问题:有些时候在改变数据后立即要对dom进行操作,此时获取到的dom仍是获取到的是数据刷新前的dom,无法满足需要,这个时候就用到了$nextTick。

 

// 修改数据

vm.msg = 'Hello'

// DOM 还没有更新

Vue.nextTick(function () {

// DOM 更新了

})

 

// 作为一个 Promise 使用 (2.1.0 起新增,详见接下来的提示)

Vue.nextTick()

.then(function () {

// DOM 更新了

})

 

vue中minxin的作用

vue中提供了一种混合机制--mixins,用来更高效的实现组件内容的复用。

 

vue相关生命周期

1、vue生命周期和生命周期钩子函数:

vue的生命周期:vue实例从创建到销毁,也就是从开始创建、初始化数据、编译模板、挂在DOM->渲染、更新->渲染、卸载等一系列过程

在这个过程中也会运行一些叫做生命周期钩子函数,在不同阶段添加自己代码的机会。

生命周期钩子函数(11个)

beforeCreate 在实例初始化之后,数据观测(dataobserver)和event/watcher事件配置之前被调用。

created 在实例创建完成后被立即调用,在这一部,实例已经完成了以下的配置,数据感测,属性和方法运算,watch/event事件回调。然而,挂载阶段还没开始,$el属性目前不可见。 http请求建议在该生命周期发出。

beforeMount 在挂载开始之前被调用:相关的render函数首次被调用。

mounted el被新创建的vm.$el替换,并挂载到实例上去之后调用改钩子。如果root实例挂载一个文档内原色,当mounted被调用时,vm.$el也在文档内

beforeUpdate 数据更新时被调用,发生在虚拟DOM打补丁之前。这里适合在更新之前访问现有的DOM,比如手动移出已添加的事件监听器。该钩子在服务器渲染期间不被调用,因为只有初次渲染会在服务器端进行。

updated 由于数据更改导致的虚拟DOM重新渲染和打补丁,在这之后会调用该钩子。

activated keep-alive组件激活时调用。该钩子在服务器端渲染期间不被调用。

deactivted keep-alive组件停用时调用。该钩子在服务器端渲染期间不被调用。

beforeDestory 实例销毁之前调用,在这一步,实例仍然完全可用。该钩子在服务器端渲染期间不被调用。

destoryed vue实例销毁后调用,调用后,vue实例指示的所有东西多会解绑定,所有的时间监听会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。

errorCaptured 2.5新增,(err:Error,vm:Component,info:string)=>?boolean 当捕获一个子孙组件的错误时被调用。

 

vue中对于对象的更改检测

由于javascript的限制,vue不能检测对象属性的添加和删除

对于已经创建的实例,vue不能动态添加根界别的响应式属性。但是可以使用Vue.set(object,key,value)方法向嵌套对象添加响应式属性。该钩子在服务器端渲染期间不被调用。

 

vue计算属性和缓存和方法调用有什么区别

1、计算属性必须返回结果

2、计算属性是基于它的依赖缓存。一个计算属性所依赖的数据发生变化时,它才会重新取值。

3、使用计算属性还是methods取决于是否需要缓存,当遍历大数组和做大量计算时,应当使用计算属性。

4、计算属性是根据依赖自动执行的,method需要事件调用。

 

computed: 计算属性是基于它们的依赖进行缓存的,只有在它的相关依赖发生改变时才会重新求值

对于 method ,只要发生重新渲染,method 调用总会执行该函数

 

v-model实现机制

我们先简单说下v-model的机制:v-model会把它关联的响应式数据(如info.message),动态地绑定到表单元素的value属性上,然后监听表单元素的input事件:当v-model绑定的响应数据发生变化时,表单元素的value值也会同步变化;当表单元素接受用户的输入时,input事件会触发,input的回调逻辑会把表单元素value最新值同步赋值给v-model绑定的响应式数据。

 

computed中的getter和setter

computed: {

fullName: {

// getter

get: function () {

return this.firstName + ' ' + this.lastName

},

// setter

set: function (newValue) {

var names = newValue.split(' ')

this.firstName = names[0]

this.lastName = names[names.length - 1]

}

}

}

 

watch监听对象

如果只是监听obj内的某一个属性变化,可以直接obj.key进行监听。

watch: {

'obj.question': function (newQuestion, oldQuestion) {

this.answer = 'Waiting for you to stop typing...'

this.debouncedGetAnswer()

}

}

如果对整个obj深层监听

watch: {

obj: {

handler: function (newQuestion, oldQuestion) {

this.answer = 'Waiting for you to stop typing...'

this.debouncedGetAnswer()

},

deep: true,

immediate: true

}

}

immediate的作用:当值第一次进行绑定的时候并不会触发watch监听,使用immediate则可以在最初绑定的时候执行。

 

 

完整的vue-router导航解析流程

导航被触发-->在失活的组件里调用离开守卫-->调用全局beforeEach守卫-->在重用的组件里调用 beforeRouteUpdate 守卫(2.2+)-->在路由配置里调用beforeEnter-->解析异步路由组件-->在被激活的组件里调用beforeRouteEnter-->调用全局的beforeResole守卫(2.5+)-->导航被确认-->调用全局afterEach --> 触发DOM更新 --> 用创建好的实例调用beforeRouteEnter守卫中传给next的回调函数

 

$route和$router的区别

$route 是“路由信息对象”,包括path,params,hash,query,fullPath,matched,name等路由信息参数

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

 

vue中key值得作用

当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。key的作用主要是为了高效的更新虚拟DOM。

key的作用是为了在diff算法执行时更快的找到对应的节点,提高diff速度

 

key具有唯一性

vue中循环需加 :key=“唯一标识” ,唯一标识可以使item里面id index 等,因为vue组件高度复用增加key可以标识组件的唯一性,为了更好地区别各个组件key的作用主要是为了高效的更新虚拟DOM

不带有key,并且使用简单的模板,基于这个前提下,可以更有效的复用节点,diff速度来看也是不带key更加快速的,因为带key在增删节点上有耗时。这就是vue文档所说的默认模式。但是这个并不是key作用,而是没有key的情况下可以对节点就地复用,提高性能。这种模式会带来一些隐藏的副作用,比如可能不会产生过渡效果,或者在某些节点有绑定数据(表单)状态,会出现状态错位。VUE文档也说明了。还有就是key的作用是为了在diff算法执行时更快的找到对应的节点,提高diff速度,但是这个含有争议。

 

 

<keep-alive></keep-alive>的作用是什么?

<keep-alive></keep-alive> 包裹动态组件时,会缓存不活动的组件实例,主要用于保留组件状态或避免重新渲染。

大白话: 比如有一个列表和一个详情,那么用户就会经常执行打开详情=>返回列表=>打开详情…这样的话列表和详情都是一个频率很高的页面,那么就可以对列表组件使用<keep-alive></keep-alive>进行缓存,这样用户每次返回列表的时候,都能从缓存中快速渲染,而不是重新渲染

 

vue.cli中怎样使用自定义的组件?有遇到过哪些问题吗?

第一步:在components目录新建你的组件文件(smithButton.vue),script一定要export default {

第二步:在需要用的页面(组件)中导入:import smithButton from ‘../components/smithButton.vue’

第三步:注入到vue的子组件的components属性上面,components:{smithButton}

第四步:在template视图view中使用,<smith-button> </smith-button>

问题有:smithButton命名,使用的时候则smith-button。

 

vue-loader是一个webpack的加载器,允许你将一个组件的所有HTML、JavaScript和CSS代码编写到同一个文件中

 

什么是vuex

vuex是一个专为vue.js应用程序开发的状态管理器,采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

解决的问题:

有了vue-router,可以将一个组件视为一个页面来使用。由于组件只维护自身的状态(data),组件创建时或者说进入路由时它们被初始化,切换至其他的组件页时当前页自然要被销毁,从而导致data也随之销毁。

页面与页面之间总会产生各种需要的共享变量,如果通过$router.param或者$router.meta来传递是远远不够的,很多情况下不得不采用window来保存一些全局的共享变量。

这样出现的问题:vue是不会维护window的这些共享变量的。对于组件来讲,这些变量都存在于组件作用域以外,组件并不会自动维护,这样就违背了js编程规范或者风格规范的一条基本准则:全局变量是毒瘤,是具有极高副作用的。

当我们将window内的对象绑定到不同的自定义组件内,一旦要对window内的变量进行修改,会发现所有以对象方式绑定的自定义组件,当对象内的某个属性发生改变时将不会执行自动刷新,所有的计算属性也同时失效!更诡异的是这种情况并不是绝对出现的,当页面元素相对简单的时候一切都显得很正常,一旦页面元素增多,对应的交互操作增多时,这种奇怪的现象就会发送。

vuex就是专门解决页面与页面之间需要的共享变量的创建、维护、变更问题的。

 

vuex的核心概念

vuex的应用核心就是store(仓库)。"store"基本上就是一个容器,它包含着你的应用中大部分的状态(state)

 

vuex和单纯的全局对象有以下两点不同

1、vuex的状态存储是响应式的,当vue组件从store中读取状态的时候,若store中的状态发生变化,那么相应的组件也会相应的得到高效更新。

2、你不能直接改变store的状态。改变store中的状态的唯一途径就是显示提交(commit)mutation。这样使得我们可以方便的跟踪每一个状态的变化。

 

vuex的核心概念

1、state -- vuex store 实例的根状态对象,用于定义共享的状态变量

2、action -- 动作,向store发出调用通知,执行本地或者远端的某一个操作(可以理解为store的methods)

3、Mutations -- 修改器,它只用于修改state中定义的状态变量

4、geeter -- 读取器,外部程序通过它获取变量的具体值,或者在取值前做一些计算(可以认为是store的计算属性)

 

vue 等单页面应用的优缺点

优点:

  • 良好的交互体验
  • 良好的前后端工作分离模式
  • 减轻服务器压力

缺点:

  • SEO难度较高
  • 前进、后退管理
  • 初次加载耗时多

 

 

1.与AngularJs的区别

相同点:都支持指令,内置指令和自定义指令;都支持过滤器:内置过滤器和自定义过滤器;都支持双向数据绑定,都不支持低端浏览器;

不同点:AngularJs的学习成本高,比如Dependency、Injecttion特性,而vue.js本身提供的API都比较简单、直观;在性能上,AngularJs依赖对数据做脏检查,所以watcher越多越慢;Vue.js使用基于依赖追踪的观察并且使用异步队列更新,所以的数据都是独立触发的。

2. 与React的区别

相同点:

React采用独特的JSX语法,Vue.js 在组件开发中也推崇编写.vue特殊文件格式,对文件内容都有一些约定,两者都需要编译后使用;中心实现相同:一切都是组件,组件实例之间可以嵌套;都提供合理的钩子函数,可以让开发者定制化底去处理需求,都不内置列数Ajax,Route等功能到核心包,而是以插件的方式加载;在组件开发中都支持mixins的特性了;

不同点:

React采用Virtual DOM会对渲染出来的结果做脏检查;Vue.js在模板中提供了指令,过滤器等,可以非常方便,快捷的操作Virtual DOM。

展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 游动-白 设计师: 上身试试
应支付0元
点击重新获取
扫码支付

支付成功即可阅读