当前位置:   article > 正文

Vue2源码解析实现—Vue响应式实现(对data中对象的属性劫持)_data数据数组中有对象,会劫持吗

data数据数组中有对象,会劫持吗

Vue2源码解析实现

Vue响应式实现

  • Vue响应式原理
    vue 实现数据响应式 ,是通过数据劫持侦测数据变化,发布订阅模式进行依赖收集与视图更新,Observe实现数据劫持,递归给对象属性,绑定setter和getter函数
  • 实现机制
    Vue的双向绑定实现机制核心:
    • 依赖于Object.defineProperty()实现数据劫持
    • 订阅模式
  • Vue2源码实现 —— 对data中对象的属性劫持

1. 创建一个index.js作为入口文件,创建一个Vue函数,并且抽离初始化文件进行模块化

import { initMixin } from "./init"; // 初始化 抽离模块化

function Vue(options) {
  // new Vue 时是进行初始化
  this._init(options);
}

initMixin(Vue);

export default Vue;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

2. 创建初始化文件init.js,在Vue函数的实例上创建一个_init方法进行初始化状态

import { initStates } from "./initState";

export function initMixin(Vue) {
  Vue.prototype._init = function (options) {
    let vm = this;
    vm.$options = options;
    // 初始化状态
    initStates(vm);
  };
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

3. 创建初始化状态文件initState.js,在这里面写所有的初始化方法(data,props,watch,methods…)

import { observer } from "./observer/index";

export function initStates(vm) {
  let opts = vm.$options;
  if (opts.data) {
    initData(vm);
  }
  if (opts.props) {
    initProps(vm);
  }
  if (opts.watch) {
    initWatch(vm);
  }
  if (opts.computed) {
    initComputed(vm);
  }
  if (opts.methods) {
    initMethods(vm);
  }
}

//! Vue2 对data进行初始化
function initData(vm) {
  //> 会有两种初始化方式 1. 对象  2. 函数
  let data = vm.$options.data;
  data = vm._data = typeof data === "function" ? data.call(vm) : data;
  //> 对数据data进行劫持
  observer(data);
}

function initProps() {}
function initWatch() {}
function initComputed() {}
function initMethods() {}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

4. 创建一个文件夹observer里面的index.js,在这里面进行数据的劫持和发布订阅模式

export function observer(data) {
  //> 判断data是否是对象或者空
  if (typeof data != "object" || data == null) {
    return data;
  }

  //> 1. 对象通过一个类
  return new Observer(data);
}

//> vue2 进行劫持是通过Object.defineProperty()  //! 缺点:只能是对象中的一个属性进行劫持 懒劫持
class Observer {
  constructor(value) {
    //> 进行遍历 让每一个属性都劫持到
    this.walk(value);
  }
  walk(data) {
    //> keys 是对象所有的属性
    let keys = Object.keys(data);
    for (let i = 0; i < keys.length; i++) {
      //> 对我们每一个属性进行劫持
      const key = keys[i];
      const value = data[key];
      //   console.log(value);
      defineReactive(data, key, value);
    }
  }
}

//> 对对象属性进行劫持
function defineReactive(data, key, value) {
  observer(value); //! 进行递归 ,深层次的劫持
  Object.defineProperty(data, key, {
    get() {
      return value;
    },
    set(newValue) {
      if (newValue == value) return;
      observer(newValue); // 如果用户设置的值是对象,也要进行劫持
      value = newValue;
    },
  });
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 总结
    1. 需要多data数据进行判断,是对象还是函数,如果是函数就要改变this执行为vm
    2. Object.defineProperty 有缺点,只能对对象中的一个属性进行劫持 所以进行遍历
    3. 递归 将深层次的数据进行get set劫持

  • 运行

    为了方便打印查看是否进行数据劫持 在vm实例上添加_data属性存放data数据
    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/248160
推荐阅读
相关标签
  

闽ICP备14008679号