vue数据监听和劫持

vue数据监听和劫持

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的数据响应有很大帮助,复制到编辑器里,静下来理一理,你会发现顿悟一样。

(完)

来源:coding个人笔记,本文观点不代表自营销立场,网址:https://www.zyxiao.com/p/96351

发表评论

电子邮件地址不会被公开。 必填项已用*标注

侵权联系
分享本页
返回顶部