第十一节:实现对data中的对象的属性进行劫持

72 阅读1分钟

入口文件 index.js

import { initMixin } from './init'
function Vue(options) {
  // 初始化
  this.__init(options);
}

initMixin(Vue);//初始化

export default Vue

初始化文件 init.js

import { initState } from './initState.js';
// 初始化业务
export function initMixin(Vue) {
  // 原型上添加初始化方法
  Vue.prototype.__init = function(options) {
    let vm = this;// this -> vue实例
    vm.$options = options;
    // 初始化状态
    initState(vm);
  }
}

初始化状态 initState.js

import { observer } from './observer/index'
// 初始化状态
export function initState(vm) {
  let ops = vm.$options;
  // 1.判断属性是否存在
  if(ops.data) {
    initData(vm);//初始化data
  }
}

// 初始化data
function initData(vm) {
  // 1.获取data
  let data = vm.$options.data;
  // 2.判断是 对象 or 函数 用call来绑定this
  data = vm._data = typeof data === 'function' ? data.call(vm) : data;
  // 3.数据劫持
  observer(data);
}

数据劫持 observer/index.js

export function observer(data) {
  // 1.判断data不是object不做劫持
  if(typeof data != 'object' || data == null ) {
    return data;
  }
  // 2.**对象 通过一个类劫持**
  return new Observer(data);
}

//  Object.defineProperty
class Observer {
  constructor(value) {
    this.walk(value);
  }
  walk(data) {
    let keys = Object.keys(data);
    for(let i = 0; i < keys.length; i++) {
      // 对我们的每个属性进行劫持
      let key = keys[i];//属性
      let value = data[key];//属性值
      defineReactive(data, key, value);
    }
  }
}

/**
 * 对对象中的属性进行劫持
 * @param {*} data
 * @param {*} key 
 * @param {*} value 
 */
function defineReactive(data, key, value) {
  // 可能是个对象就需要递归了: **深度劫持**
  observer(value);
  Object.defineProperty(data, key, {
    get() {
      return value;
    },
    set(newValue) {
      // 设置的值相同
      if(newValue === value) return value;
      observer(value);//**避免对象替换地址失去劫持** a = {}
      value = newValue;
    }
  })
}