手写Vue (1) 对象劫持

1.引入咱们手写的Vue 拿到配置数据vue

import Vue from '../source/src/index';
let vm = new Vue({
  el: '#app',
  data() {
    return {
      msg: 'hello',
      school: {
        name: 'zf',
        age: 10
      },
      arr: [1, 2, 3]
    }
  },
  computed: {

  },
  watch: {

  }
})
console.log(vm)
// setTimeout(() => {
//   vm.arr[0].push(100)
//   console.log(vm)
// }, 1000)

2. 新建文件    source/src/index  数组

在这个文件中 咱们利用 ——init 这个方法 对 用户传入的数据进行初始化 传入配置信息app

function Vue(options) {
  // console.log(options)
  // 初始化vue
  this._init(options)
}

3. 在_init 方法中 咱们能够先将  options 挂载到实例  再进行初始化数据操做 函数

Vue.prototype._init = function (options) {
  // vue 的初始化
  let vm = this;
  // 将 options 挂载到实例
  vm.$options = options;
  //须要数据从新初始化
  initState(vm)
}

5. 新建 文件  observe/index 编写  initState  方法而且导出测试

export function initState(vm) {
  console.log(vm)
}

在这里咱们能够拿到 vue 的整个实例方法 this

6. 在initState  方法中 咱们进行初始化  好比初始化 数据 初始化 计算属性 初始化 watch spa

 

export function initState(vm) {
  // 拿到option  存储起来
  let options = vm.$options;
  if (options.data) {
    // 初始化数据
    initData(vm)
  }
  if (options.computed) {
    // 初始化计算属性
    initComputed()
  }
  if (options.watch) {
    // 初始化watch
    initWatch()
  }
}

 

7. 初始化数据 在    initData  方法中 咱们经过 传入实例的option 拿到数据 再判断 数据 是 函数 仍是 对象 若是是函数 调用call 方法 拿到函数 返回值 如何不是直接返回数据 或者 空数据 prototype

 let data = vm.$options.data
  // 判断是不是函数 取返回值
  data = vm._data = typeof data === 'function' ? data.call(vm) : data || {}

 

8. 拿到数据后 咱们要对数据进行 监听 编写   observe  方法 监听数据 、3d

 

function initData(vm) {
  let data = vm.$options.data
  // 判断是不是函数 取返回值
  data = vm._data = typeof data === 'function' ? data.call(vm) : data || {}
  observe(vm._data)
}

 

10 在  observe 方法中 要进行判断 看看数据是否是对象或者为空 若是不是 直接返回 若是是 返回一个  Observe 对象 代理

export function observe(data) {
  // 不是对象或者是null
  if (typeof data !== 'object' || data === null) {
    return
  }
  return new Observe(data)
}

 

11. 编写这个  Observe 对象   新建文件 Observe.js

这个文件里面最主要的是   Object.defineProperty 方法 里面传入 data , 还有key  key 表明属性 因此 咱们须要遍历数据 拿到 全部的 key value 传入 

class Observe {
  constructor(data) {
    // 数组 重写push 方法
    if (Array.isArray()) {
    } else {
      // 对象
      // data 就是咱们 定义的 vm._data 的数据
      this.walk(data)
    }
  }
  //将对象的数据使用 defineProperty 从新定义 
  walk(data) {
    let keys = Object.keys(data);
    for (let i = 0; i < keys.length; i++) {
      let key = keys[i];  // key
      let value = data[keys[i]];  // value
      defineReactive(data, key, value)
    }
  }
}
export function defineReactive(data, key, value) {
  Object.defineProperty(data, key, { get() { // 有值
      return value; }, set(newValue) { if (newValue !== value) return; value = newValue } })
}
export default Observe;

 

11.  由于 数据里面 的对象 可能嵌套 一个对象 因此咱们应该在 数据里面的对象再进行 深度监听 

 
 
import { observe } from './index'

export function defineReactive(data, key, value) { observe(value); Object.defineProperty(data, key, {
get() { // 有值 return value; }, set(newValue) { if (newValue !== value) return; value = newValue } }) }

12. 测试代码 

import Vue from '../source/src/index';
let vm = new Vue({
  el: '#app',
  data() {
    return {
      msg: 'hello',
      school: {
        name: 'zf',
        age: 10
      },
      arr: [1, 2, 3]
    }
  },
  computed: {

  },
  watch: {

  }
})
console.log(vm._data.msg)  // hello

打印出100 

13.  这里每次取值都须要 挂在 _data 上  很 不方便 好比 

vm._data.msg  咱们简化为 vm.msg 
 
因此 咱们能够 利用  proxy 代理 _data  代理应该在 初始化数据 的操做中 监听数据前
function initData(vm) {
  let data = vm.$options.data
  // 判断是不是函数 取返回值
  data = vm._data = typeof data === 'function' ? data.call(vm) : data || {}
  for (let key in data) { proxy(vm, "_data", key) }
  observe(vm._data)
}

14, 编写 proxy  方法

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

15。测试成功 

import Vue from '../source/src/index';
let vm = new Vue({
  el: '#app',
  data() {
    return {
      msg: 'hello',
      school: {
        name: 'zf',
        age: 10
      },
      arr: [1, 2, 3]
    }
  },
  computed: {

  },
  watch: {

  }
})
console.log(vm.msg)  // hello
相关文章
相关标签/搜索