likes
comments
collection
share

Vue 2中的数据劫持

作者站长头像
站长
· 阅读数 10

简介

在Vue.js这个前端框架中,数据劫持是一个核心概念,它使得Vue能够实时响应数据的变化并更新视图。在Vue 2中,数据劫持的实现主要依赖于JavaScript的Object.defineProperty方法。

示例

在vue中,我们是这样构建实例的(代码中的data直接是一个对象,而不是一个函数)。

const vm = new Vue({
  el: '#app',
  data: {
    name: 'w',
    age: 18,
    sex: '男',
    other: {
      a: 'aaa'
    },
    likes: ['篮球', '足球', '乒乓球']
  }
});

实现Vue方法

// Vue.js
class Vue {
  constructor(options) {
    const { data } = options;
    this.$options = options;
    this.$data = data;
  }
}

export default Vue;

使用Observer监听数据

// Observer.js
class Observer {
  constructor(data) {
    this.walk(data);
  }
  walk(data) {
    for (const [key, value] of Object.entries(data)) {
      this.defineReactive(data, key, value);
    }
  }
  // 监听
  defineReactive(target, key, value) {
    Object.defineProperty(target, key, {
      get() {
        return value;
      },
      set(newValue) {
        value = newValue;
      }
    })
  }
}

export default Observer;
// Vue.js
import Observer from './Observer.js';

class Vue {
  constructor(options) {
      const { data } = options;
      new Observer(data);
      ...
      
  }
}

我们打印vm实例,可以看到$data中的基础类型已经被绑定了getset。而引用数据类型没有被绑定get和set。

Vue 2中的数据劫持

接下来处理引用类型的数据监听

// Objserver.js
class Observer {
  ...
  walk(data) {
    if (typeof data !== "object" || data == null) {
      return
    }
    ...
  }
  defineReactive(target, key, value) {
    this.walk(value);
    ...
  }
}

打印vm实例,我们可以看到likesother也被绑定了getset

Vue 2中的数据劫持

代理机制

通过代理机制实现vm.xxx即可直接访问vm.$data.xxx

// Vue.js
class Vue {
    constructor(options) {
        ...
        this.proxyData();
      }
    proxyData()  {
      for (const key in this.$data) {
        Object.defineProperty(this, key, {
          get() {
            return this.$data[key];
          },
          set(newValue) {
            this.$data[key] = newValue;
          }
        })
      }
    }
}

Vue 2中的数据劫持

监听数组变化

我们通过vm.likes.push('羽毛球'),发现push的数据没有被添加get和set。

Vue 2中的数据劫持

// arrayPrototype.js
import Observer from "./Observer.js";

const arrayPrototype = Object.create(Array.prototype);

['push', 'pop'].forEach(method => {
  arrayPrototype[method] = function (...args) {
    Array.prototype[method].apply(this, args);
    new Observer(this);
  }
})

export default arrayPrototype;

通过重新设置数组的原型,实现修改数组时的数据劫持。

// Observer.js
import arrayPrototype from './arrayPrototype.js';

class Observer {
  ...
  walk(data) {
    ...
    if (data instanceof Array) {
      Object.setPrototypeOf(data, arrayPrototype)
    }
    ...
  }
  ...
}

Vue 2中的数据劫持

通过重新设置数组的原型,我们可以看到push的数据已经绑定了getset了。

总结

本文介绍了Vue.js中对数据进行劫持的基本概念,希望对大家有所帮助。

转载自:https://juejin.cn/post/7352708237844103220
评论
请登录