vue数据监听和劫持

作者: wade3po | 来源:发表于2020-04-08 16:36 被阅读0次

vue对数据的监听都知道是通过Object.defineProperty,今天简单把过程捋了一下,弄清楚vue对数据的处理。

//index.js
//声明vue构造函数,进行初始化
function Vue(options) {
 this._init(options);
}

Vue.prototype._init = function (options) {
 //定义一个vm
 let vm = this;
 vm.$options = options;
 //初始化
 initState(vm);
}

//observe/index.js
function initState(vm) {
 //初始化props methods data computed watch
 let opts = vm.$options;
 if(opts.data){
  initData(vm);
 }
 // if(opts.watch){
 //   initWatch(opts.watch);
 // }
}

function initData(vm) {
 let data = vm.$options.data;
 //挂载data到vm_data,不改变原data
 data = vm._data = typeof data === 'function' ? data.call(vm) : data || {};
 //代理data上的数据到_data
 for (let key in data) {
  proxy(vm, '_data', key)
 }
 //数据进行观察
 observe(vm._data);
}

function proxy(vm, source, key) {
 Object.defineProperty(vm, key, {
  get(){
   return vm[source][key];
  },
  set(newValue){
   vm[source][key] = newValue;
  }
 })
}

function observe(data) {
 //如果不是对象,就不进行监听{a:5},监听了a,不监听5
 if(typeof data !== 'object' || data === null){
  return
 }
 return new Observer(data);
}

//observe/observer.js
function Observer(data) {
 //如果是数组另外处理
 if(Array.isArray(data)){
  //劫持数组方法
  data.__proto__ = arrrayMethods;
  //数组每一项进行监听
  observerArray(data);
 }else{
  //对象进行监听
  this.walk(data);
 }
}
Observer.prototype.walk = function (data) {
 let keys = Object.keys(data);
 for (let i = 0; i < keys.length; i++) {
  defineReactive(data, keys[i], data[keys[i]]);
 }
}

//核心代码,对对象进行监听
function defineReactive(data, key, value) {
 //判断,如果对象里面嵌套对象,递归监听
 //vue一个性能痛点,vue3用proxy改进,proxy兼容会有点问题
 observe(value);
 //核心
 Object.defineProperty(data, key, {
  get(){
   console.log('get---' + key + '---' + value);
   return value;
  },
  set(newValue){
   console.log('set---' + key + '---' + value);
   if(value === newValue){
    return
   }
   value = newValue;
  }
 })
}

//observe/array.js
let arrayProto = Array.prototype;
//拷贝数组方法
let arrrayMethods = Object.create(arrayProto);
let changeMethods = ['push', 'pop', 'unshift', 'shift', 'sort', 'reverse', 'splice'];
changeMethods.forEach(method => {
 //对七个会改变原数组的方法进行劫持,切片编程
 arrrayMethods[method] = function (...args) {
  let inserted;
  switch (method) {
   case 'push':
   case 'unshift':
    inserted = args;
    break;
   case 'splice':
    inserted = args.splice(2);
    break;
   default:
    break;
  };
  //对于新增的数组项进行监听
  if(inserted) observerArray(inserted);
  //最终还是调用数组原方法
  return arrayProto[method].apply(this, args);
 }
})

function observerArray(inserted) {
 for (let i = 0; i < inserted.length; i++) {
  observe(inserted[i]);
 }
}

然后就可以去调用:

let vm = new Vue({
 data(){
  return {
   msg: 'hello',
   obj: {a: 10},
   arr: [1, 2, 3]
  }
 },
 methods:{},
})

console.log(vm.$options);

这边只是很简单的理了一下,源码大概也能找到这些方法,源码当然更复杂,把方法都写到一起了,如果是npm包的话是通过import和export导入导出,这边也有把划分的写了一下。

真的觉得好好理解一下,对于vue的数据响应有很大帮助,复制到编辑器里,静下来理一理,你会发现顿悟一样。

image

相关文章

  • vue数据监听和劫持

    vue对数据的监听都知道是通过Object.defineProperty,今天简单把过程捋了一下,弄清楚vue对数...

  • Vue3.0 API的使用

    Vue3.0 整体优势 proxy数据劫持代替object.defineProperty(特点:可以监听数组变化,...

  • vue中的变化检测问题

    从vue通过Object.defineProperty方法劫持数据可知,vue是监听不到对象属性的增加或删除的,因...

  • 数据监听

    上次我们实现了一个数据劫持,今天我们看一下数据的监听。什么是监听呢?请看以下代码: 劫持和监听的区别在于:劫持是针...

  • vue.js响应式原理解析与实现—实现v-model与{{}}指

    上次我们已经分析了vue.js是通过Object.defineProperty以及发布订阅模式来进行数据劫持和监听...

  • 关于 Vue 和 React 区别

    监听数据变化的实现原理不同 Vue 通过 getter/setter 以及一些函数的劫持,能精确知道数据变化,不需...

  • 自己动手实现MVVM

    1、数据劫持(vue):通过Object.defineProperty()去劫持数据每个属性对应的getter和s...

  • 详解defineProperty和Proxy (简单实现数据双向

    前言 "数据绑定" 的关键在于监听数据的变化,vue数据双向绑定是通过数据劫持结合发布者-订阅者模式的方式来实现的...

  • Vue3 为什么要用 Proxy 代替 Object.defin

    Object.defineProperty 劫持数据 只是对对象的属性进行劫持 无法监听新增属性和删除属性需要使用...

  • VUE的双向绑定原理

    数据劫持(vue.js) 1.vue.js 则是采用数据劫持结合发布者-订阅者模式的方式,通过对象的定义属...

网友评论

    本文标题:vue数据监听和劫持

    本文链接:https://www.haomeiwen.com/subject/tpntmhtx.html