返回

Vue.js 2.x 数据劫持详解

前端

在构建响应式应用程序时,Vue.js 2.x 利用数据劫持技术在幕后发挥着至关重要的作用。数据劫持允许 Vue 追踪数据属性的变化,并在发生变化时自动更新界面。本文将深入探讨 Vue.js 2.x 中数据劫持是如何实现的。

数据劫持的原理

数据劫持本质上是一种代理模式。Vue 通过代理目标对象来拦截对目标对象属性的获取和设置操作。代理对象实现了与目标对象相同的接口,但在操作目标对象属性时触发了额外的逻辑。

Object.defineProperty() 的作用

Vue 使用原生 JavaScript 的 Object.defineProperty() 方法来拦截属性的获取和设置操作。Object.defineProperty() 允许定义或修改对象的属性符,包括是否可枚举、可配置和可写入。

在数据劫持中,Vue 利用 Object.defineProperty() 为目标对象上的每个属性定义一个 getter 和 setter。getter 负责在获取属性值时通知 Vue 依赖跟踪系统,而 setter 负责在设置属性值时触发更新。

getter 和 setter 函数

Vue 定义的 getter 和 setter 函数如下:

// getter
function getter() {
  // 触发依赖跟踪系统
  track();
  // 返回属性值
  return value;
}

// setter
function setter(newValue) {
  // 触发依赖跟踪系统
  trigger();
  // 更新属性值
  value = newValue;
}

getter 函数在获取属性值时触发依赖跟踪系统,以便 Vue 可以将当前组件添加到属性的依赖列表中。当属性值发生变化时,setter 函数触发更新,通知 Vue 依赖的组件重新渲染。

数据劫持的实现

Vue.js 在 src/core/instance/state.js 中实现了数据劫持。当创建一个 Vue 实例时,Vue.set() 方法被调用来遍历实例的属性并为每个属性定义 getter 和 setter。

export function set(target: object, key: string, val: any) {
  if (hasOwn(target, key)) {
    const oldVal = target[key];
    if (val === oldVal) {
      return;
    }
    // ...
    // 定义 getter 和 setter
    // ...
    target[key] = val;
    // 触发更新
    dep.notify();
  } else {
    // ...
  }
}

总结

Vue.js 2.x 的数据劫持通过代理目标对象并使用 Object.defineProperty() 定义 getter 和 setter 函数来实现。getter 触发依赖跟踪,setter 触发更新。这种机制允许 Vue 追踪数据属性的变化并自动更新界面,从而实现响应式应用程序。