定制软件3_Vue面试题

目录

1. 定制软件你怎样理解Vue

Vue通过MVVM定制软件思想实现数据的,定制软件数据驱动页面视图。

  • Vue定制软件是数据驱动的框架,定制软件我们不必纠结于DOM定制软件元素的获取与操作,定制软件变动数据时,Vue定制软件的底层会自动的帮助我定制软件们更新视图层。(VM定制软件这一层不必我们去操作)
  • JQuery定制软件中我们是面向DOM开发,Vue定制软件是面向数据开发(Model层最重要,其次View层)

MV-VM的理解

  • Model-View-ViewModel
    • Model - 数据层,定制软件如计数器案例中的obj定制软件或是从网络上请求的数据
    • View - 视图层,DOM层
    • ViewModel - 视图模型 - 是Model与View定制软件沟通的桥梁
      • 定制软件定制软件一方面实现Data Binding,数据绑定,将Model定制软件的改变反应到View中;
      • 一方面实现DOM Listening,监听到DOM中的事件,定制软件并根据情况更改对应Data

Vue定制软件是怎么实现VM层的

  • 虚拟DOM
  • Object.defineProperty
    • 定制软件当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 定制软件将遍历此对象所有的 property,并使用 把这些 property 全部转为 。Object.defineProperty 是 ES5 中的特性,这也就是 Vue 不支持 IE8 定制软件以及更低版本浏览器的原因。

2.

定制软件是通过采用数据劫持结合发布者-定制软件订阅者模式定制软件的方式来实现的。通过Object.defineProperty()定制软件来劫持各个属性的setter,getter。修改触发set方法赋值,获取触发get方法取值,定制软件在数据变动时发布消息给订阅者,定制软件触发相应的回调并通过定制软件数据劫持发布信息。

Vue 定制软件主要通过以下 4 定制软件个步骤来实现数据双向绑定的:

  • 定制软件实现一个监听器 Observer:定制软件对数据对象进行遍历,定制软件包括子属性对象的属性,利用 Object.defineProperty() 定制软件对属性都加上 setter 和 getter。这样的话,定制软件给这个对象的某个值赋值,就会触发 setter,定制软件那么就能监听到了数据变化。

  • **实现一个解析器 Compile:**解析 Vue 模板指令,将模板中的变量都替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,调用更新函数进行数据更新。

  • **实现一个订阅者 Watcher:**Watcher 订阅者是 Observer 和 Compile 之间通信的桥梁 ,主要的任务是订阅 Observer 中的属性值变化的消息,当收到属性值变化的消息时,触发解析器 Compile 中对应的更新函数。

  • **实现一个订阅器 Dep:**订阅器采用发布-订阅 设计模式,用来收集订阅者 Watcher,对监听器 Observer 和 订阅者 Watcher 进行统一管理。


3. v-model双向绑定的原理

v-model 本质上不过是语法糖。它负责监听用户的输入事件以更新数据。

Object.defineproperty()重新定义(set方法)对象设置属性值和(get方法)获取属性值的操纵来实现的。

  1. 实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者
  2. 实现一个订阅者Watcher,可以收到属性的变化通知并执行相应的函数,从而更新视图。
  3. 实现一个解析器Compile,可以扫描和解析每个节点的相关指令,并根据初始化模板数据以及初始化相应的订阅器。

4. Vue不能检测数组和对象的变化

因为 Vue 会在初始化实例时对 property 执行 getter/setter 转化,所以 property 必须在 data 对象上存在才能让 Vue 将它转换为响应式的。

追问:如何解决上述问题?

对于对象:

Vue.set(vm.someObject, 'b', 2)
  • 1

也可以使用 vm.$set 实例方法,这也是全局 Vue.set 方法的别名:

this.$set(this.someObject,'b',2)this.$delete(this.someObject,'b') 删除旧属性
  • 1
  • 2

添加多个属性:( 直接使用Object.assign()_.extend()无法触发更新 )

应该用原对象与要混合进去的对象的 property 一起创建一个新的对象。

// 代替 `Object.assign(this.someObject, { a: 1, b: 2 })`this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })
  • 1
  • 2

对于数组:

Vue 不能检测以下数组的变动:

  1. 当你利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue
  2. 当你修改数组的长度时,例如:vm.items.length = newLength
// Vue.set或vm.$setVue.set(vm.items, indexOfItem, newValue)vm.$set(vm.items, indexOfItem, newValue)// Array.prototype.splicevm.items.splice(indexOfItem, 1, newValue)//解决第2点,splice若只设置一个参数,则从该位置开始删除后面所有值vm.items.splice(newLength)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

5. 生命周期函数

5.1 什么是生命周期(简述Vue的生命周期)

  • 生命周期函数是一些钩子函数,在某个时间会被Vue源码内部进行回调;

  • 通过对生命周期函数的回调,我们可以知道目前组件正在经历什么阶段;

  • 那么我们就可以在该生命周期中编写属于自己的逻辑代码了;

每个组件都可能会经历从创建、挂载、更新、卸载等一系列的过程,在这个过程中的某一个阶段,用于可能会想要添加一些属于自己的代码逻辑(比如组件创建完后就请求一些服务器数据)

  • 创建 create (beforeCreate / created)
  • 挂载 mount ( beforeMount / mounted)
  • 更新 update (beforeUpdate / updated)
  • 卸载 unmount (beforeUnmount / unmounted)

常见提问:

  • created表示完成数据观测、属性和方法的运算和初始化事件,此时$el属性还未显示出来
  • DOM渲染在mounted中就已经完成了

一般在created里做网络请求,在mounted做数据挂载(mounted阶段才有真实的DOM

5.2 生命周期相关题目

1)Vue 实例的 data 属性,可以在哪些生命周期中获取到?(B/C/D)

A. beforeCreate B. created C. beforeMount D. mounted


6. Vue中的diff算法

vue基于虚拟DOM做更新,diff又是其核心部分,因此常被问道,此题考查面试者深度。

  1. 定义diff

  2. 它的必要性

  3. 它在哪里被使用

  4. 它如何运作

  5. 提升:说一些细节

回答范例:

  1. diff算法是虚拟DOM技术的产物,vue里面实际叫做patch,它的核心实现来自于snabbdom;通过新旧虚拟DOM作对比(即patch),将变化的地方转换为DOM操作

  2. 在vue 1中是没有patch的,因为界面中每个依赖都有专门的watcher负责更新,这样项目规模变大就会成为性能瓶颈,vue 2中为了降低watcher粒度,每个组件只有一个watcher,但是当需要更新的时候,怎样才能精确找到发生变化的地方?这就需要引入patch才行。

  3. 组件中数据发生变化时,对应的watcher会通知更新并执行其更新函数,它会执行渲染函数获取全新虚拟dom:newVnode,此时就会执行patch比对上次渲染结果oldVnode和新的渲染结果newVnode。

  4. patch过程遵循深度优先、同层比较的策略;两个节点之间比较时,如果它们拥有子节点,会先比较子节点;比较两组子节点时,会假设头尾节点可能相同先做尝试,没有找到相同节点后才按照通用方式遍历查找;查找结束再按情况处理剩下的节点;借助key通常可以非常精确找到相同节点,因此整个patch过程非常高效。


7. 组件通信

7.1 父子组件通信

  • 父传子:props

    在开发中很常见的就是父子组件之间通信,比如父组件有一些数据,需要子组件来进行展示

  • 子传父:$emit事件

    当子组件有一些事件发生的时候,比如在组件中发生了点击,父组件需要切换内容时,就要用到子传父。

  • 除了父子组件之间的通信之外,还会有非父子组件之间的通信。

    有不止两种方式: 1. provide/inject; 2. 全局事件总线bus


8. nextTick作用与实现原理

这道题考查对vue异步更新队列的理解,有一定深度。

答题思路:

  1. nextTick是啥?下一个定义
  2. 为什么需要它呢?用异步更新队列实现原理解释
  3. 在什么地方用它呢?
  4. 下面介绍一下如何使用nextTick
  5. 最后能说出源码实现就会显得你格外优秀

官方定义:Vue.nextTick( [callback, context] )

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

// 修改数据vm.msg = 'Hello'// DOM 还没有更新Vue.nextTick(function () {// DOM 更新了})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

回答范例:

  1. nextTick是Vue提供的一个全局API,由于vue的异步更新策略导致我们对数据的修改不会立刻体现在dom变化上,此时如果想要立即获取更新后的dom状态,就需要使用这个方法

  2. Vue 在更新 DOM 时是异步执行的。只要侦听到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的。nextTick方法会在队列中加入一个回调函数,确保该函数在前面的dom操作完成后才调用。

  3. 所以当我们想在修改数据后立即看到dom执行结果就需要用到nextTick方法。

  4. 比如,我在干什么的时候就会使用nextTick,传一个回调函数进去,在里面执行dom操作即可。

  5. 我也有简单了解nextTick实现,它会在callbacks里面加入我们传入的函数,然后用timerFunc异步方式调用它们,首选的异步方式会是Promise。这让我明白了为什么可以在nextTick中看到dom操作结果。


9. 全局导航钩子函数应用场景

router.beforeEach(全局前置守卫)是页面加载之前,在每次路由改变的时候执行一遍。
router.afterEach(全局后置守卫),与上相反,是页面加载之后。

应用场景:

  1. 可进行一些页面跳转前处理,例如判断需要登录的页面进行拦截,做登录跳转。
  2. 进入页面登录判断、管理员权限判断、浏览器判断

10. computed | watch 区别

computed 计算属性 :

依赖其它属性值,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值,如果和上次计算结果不一致,重新渲染页面。

watch 侦听器 :

更多的是「观察」的作用,无缓存性,类似于某些数据的监听回调,每当监听的数据变化时都会执行回调进行后续操作。

追问:computed 和 watch 应用场景?

computed:当我们需要进行数值计算,并且依赖于其它数据时,应该使用 computed,因为可以利用 computed 的缓存特性,避免每次获取值时,都要重新计算。(computed+缓存)

watch:当我们需要在数据变化时执行的操作时使用(如调用其它函数)

追问:能使用箭头函数定义computed和watch吗?

不能,因为箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,为undefined


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

在new Vue()实例中,data 可以是对象,但在 vue 组件中,data 必须是一个函数,确保多个组件实例之间是独立的数据。如果 data 是对象,组件实例之间就共享了。

关键词: 复用 + 污染 + 函数返回 + 数据拷贝

因为组件是可以复用的,JS 里对象是引用关系,如果组件 data 是一个对象,那么子组件中的 data 属性值会互相污染,产生副作用。所以一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝。new Vue 的实例是不会被复用的,因此不存在以上问题。


其他

1. public和assets文件的异同

1. 相同点
文件夹中的资源在html中使用都是可以的。

2. 不同点

  • public中的文件,是不会经过编译的,打包后会生成dist文件夹,public中的文件只是复制一遍。因此,public建议放一些外部第三方,自己的文件放在assets,别人的放public中。

  • 若把图片放在assets和public中,html页面都可以使用,但是在动态绑定中,assets路径的图片会加载失败(因为webpack使用的是commenJS规范,必须使用require才可以。

    • 使用assets下面的资源,在js中使用的话,路径要经过webpack中的file-loader编译,路径不能直接写。

    • 使用public文件下面的资源,是不会被webpack处理的,它们会被直接复制到最终的打包目录下面,且必须使用绝对路径来引用这些文件。


网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发