vue面试题

米阳 2020-3-2 483 3/2

响应式原理

响应式原理主要通过以下三个阶段来实现:依赖追踪、依赖收集和触发更新

  1. 依赖追踪:Vue.js 在初始化时,会遍历 data 对象中的每个属性,为每个属性创建一个“依赖”(也可以叫“观察者”),并将这个依赖与属性建立关联关系。这个关联关系可以理解为属性“依赖于”这个依赖。这是通过 Object.defineProperty() 方法实现的,该方法允许精确添加或修改对象的属性,并可以在这些属性的 getter 和 setter 方法上添加自定义逻辑。
  2. 依赖收集:在组件渲染的过程中,模板中的表达式会执行对应的 getter 函数。getter 函数会把表达式中用到的属性“收集”起来,与当前的渲染上下文建立关联关系。这个关联关系可以理解为当前的渲染上下文“依赖于”这些属性。在依赖收集阶段,每个依赖都会被记录在当前的渲染上下文中,这样当数据发生变化时,就可以根据当前的渲染上下文,找到所有依赖,并依次触发它们的更新操作。每个组件实例都会对应一个 watcher 实例,它会在组件渲染的过程中把使用过的数据属性通过 getter 收集为依赖。
  3. 触发更新:当数据发生变化时,即属性的 setter 被调用时,会通知对应的 Watcher 实例,从而使它关联的组件重新渲染。这是通过触发依赖的 setter 方法实现的,当 setter 被调用时,会通知所有依赖这个属性的 Watcher 实例进行更新操作

总的来说,Vue.js 的响应式原理是通过 Object.defineProperty() 方法劫持各个属性的 setter 和 getter,在数据变动时发布消息给订阅者,触发相应的监听回调,从而实现数据驱动的视图更新。

Vue 中的 key 到底有什么用

  1. 提高 DOM 更新性能:Vue 使用 key 来标识每个节点,从而可以更精确地找到需要更新的节点。当 Vue 更新 DOM 时,它会基于新数据生成一棵新的虚拟 DOM 树,并与旧的虚拟 DOM 树进行对比。key 的存在帮助 Vue 更准确地找到需要更新的节点,而不是对整个 DOM 树进行重新渲染,从而提高了更新性能。
  2. 管理可复用的元素:Vue 会尽可能地复用已有的元素,而不是从头开始渲染。当使用 v-for 指令渲染列表时,key 的存在可以确保 Vue 准确地找到对应的节点,并根据 key 的变化重新排列元素顺序,或者移除不存在的元素。
  3. 强制重新渲染:在某些特殊场景下,可以使用 key 来强制重新渲染某个组件或元素。例如,当某个组件的数据依赖于外部环境的变化时,可以通过改变 key 的值来强制该组件重新渲染,从而确保数据的正确性。

需要注意的是,key 的值必须是唯一的,以确保 Vue 能够准确地识别每个节点。在实际使用中,通常使用数据对象的唯一标识符(如 id)作为 key 的值。同时,当使用 v-for 渲染动态数据时,为了避免 DOM 元素复用错误或渲染异常,不应直接修改数据源,而应使用变异方法或重新赋值来更新数据。

computed 的实现原理

computed 属性的实现原理主要涉及以下几个方面:

  1. 依赖收集
    当 computed 属性被访问时(例如,在模板中或通过 Vue 实例直接访问),它会触发其内部依赖的收集过程。Vue 会遍历 computed 属性的 getter 函数,执行过程中遇到的所有响应式依赖(即其他数据属性)都会被收集,并与当前的 computed 属性建立关联。

  2. 计算缓存
    computed 属性的值会被缓存起来。这意味着只要依赖属性没有发生改变,多次访问同一个 computed 属性会立即返回之前缓存的计算结果,而不会重新执行 getter 函数。这种缓存机制可以显著提高性能,特别是当 computed 属性的计算过程非常耗时或依赖于大量数据时。

  3. 依赖变化通知
    当任何一个 computed 属性所依赖的数据属性发生变化时,Vue 的响应式系统会通知这些 computed 属性,告诉它们需要重新计算。这是通过依赖收集阶段建立的关联关系来实现的。一旦收到通知,computed 属性会重新执行其 getter 函数,并更新缓存的值。

  4. 观察者模式
    computed 属性的实现基于 Vue 的观察者模式。每个响应式数据属性都有一个观察者,当数据属性变化时,观察者会通知所有依赖这个属性的 computed 属性。这种观察者模式使得 Vue 能够以非常灵活和高效的方式处理数据的依赖关系。

  5. 计算属性与方法的区别
    尽管 computed 属性和方法都可以用来处理复杂逻辑和计算,但它们之间有一个重要的区别。方法每次被调用时都会重新计算,而 computed 属性则会缓存计算结果,只有当依赖的数据发生改变时才会重新计算。这使得 computed 属性在计算复杂逻辑时更加高效。

computed 和 watch 有什么区别及运用场景

区别:

  1. 用途和功能性
    • computed 是计算属性,主要用于处理复杂逻辑和基于其他数据属性的计算。它返回一个缓存的结果,只有当依赖的数据发生变化时才会重新计算。
    • watch 用于监听单个数据属性的变化,并在数据变化时执行特定的回调函数。它主要用于异步操作或开销较大的操作。
  2. 缓存支持
    • computed 属性支持缓存,只有当其依赖的数据发生变化时,才会重新计算。如果依赖没有变化,它会从缓存中读取之前的结果。
    • watch 则不支持缓存,每次监听的数据变化时都会执行回调。
  3. 异步操作和开销
    • computed 属性不支持异步操作,因为计算属性需要同步返回结果。
    • watch 更适合执行异步操作或开销较大的操作,因为你可以在数据变化时触发这些操作。
  4. 返回值要求
    • computed 属性的函数必须使用 return 语句返回计算结果。
    • watch 的回调函数则没有这样的要求。

运用场景:

  1. 使用 computed 的场景
    • 当一个属性受多个属性影响时,例如,需要根据用户输入的长度和宽度来计算面积。
    • 当需要在数据变化时执行复杂计算,并且这些计算的结果需要被缓存以提高性能时。
  2. 使用 watch 的场景
    • 当需要监听某个数据属性的变化,并在变化时执行异步操作,例如,数据变化时发送 AJAX 请求。
    • 当一个数据属性的变化会影响多个其他数据属性时,例如,监听搜索框的输入,并根据输入内容过滤数据列表。

为什么在 Vue3.0 采用了 Proxy,抛弃了 Object.defineProperty?

  1. 更全面的拦截能力:Proxy API 支持拦截目标的各种操作,包括读取、设置、删除、枚举等,甚至还可以拦截函数调用和构造函数实例化。相比之下,Object.defineProperty 只能监听属性的 get 和 set 操作,无法覆盖其他重要的操作。

  2. 更好的数组变化检测:Vue 3.0 使用 Proxy API 改善了数组的变化检测机制。Proxy 可以直接拦截数组的索引访问和修改,使得对数组的变化更容易被监听到,从而提供了更可靠的响应式行为。相比之下,Vue 2.x 中使用 Object.defineProperty 无法检测到数组下标的变化,需要额外的逻辑来处理这个问题。

  3. 更易于处理嵌套对象:Proxy API 能够递归地拦截对象的嵌套属性,而 Object.defineProperty 无法自动递归处理嵌套对象。这使得在 Vue 3.0 中处理嵌套对象更加简单和方便。

  4. 更好的错误提示:相比于 Object.defineProperty,Proxy API 提供了更好的错误追踪和调试信息。当使用 Proxy API 时,如果访问或修改了一个不存在的属性,会直接抛出错误,从而更容易发现和修复问题。

  5. 性能优化:在某些场景下,Object.defineProperty 的实现可能会导致性能问题。而 Proxy 的性能表现通常更好,能够更高效地处理响应式操作。

- THE END -

米阳

7月17日14:44

最后修改:2024年7月17日
0

非特殊说明,本博所有文章均为博主原创。