对Vue中响应式原理个人理解

57 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

对于Object.defineProperty作用

// 这是一个普通的数据对象
let obj = {a : 10}// 先定义一个变量作为初始值,
let val = obj.a
Object.defineProperty(obj, a, {
     get() {      
       // 当访问obj中a属性会触发这里(getter)
       return val    
     },    
     set(newValue) {      
       if (val === newValue) {        
          return      
       }
      //  当修改obj中的a 属性就需要访问这里(setter)      
      val= newValue      
      console.log("改变a属性为", newValue)    
     },    
     enumerable: true,
  }
)

这时候我们会发现,当前这个方法只对a属性有效,当某一个object对象有多个key时,就需要循环遍历每个key都变成响应式,但是如果每个object[key]当中还含有多个key时,这时候就需要递归处理,(需要借鉴一下Vue的思路)

function defineReactive(obj, keyName, value) {
  if (arguments.length === 2) {
    value = obj[keyName]
  }
  
  // 调用观察函数
  observe(value)
  Object.defineProperty(obj, keyName, {
    get() {
      return value
    },
    set(newValue) {
      if (val === newValue) {
        return
      }
      value = newValue
        
      // 定义子项
      observe(newValue)
      console.log("改变a属性为", newValue)
    },
    enumerable: true,
  })
}

function def(obj, key, value, enumerable) {
  Object.defineProperty(obj, key, {
    value,
    enumerable,
    writable: true,
  })
}

class Observer {
  constructor(obj) {
    // 将observe创建出来的实例,添加到当前层对象当中
    def(obj, "__ob__", this)
    // 遍历当前对象
    this.walk(obj)
  }
  walk(obj) {
    // obj一定是个object,因为observe做了判断
    console.log(obj, "walk")

    // 定义当前层为响应式
    for (let key in obj) {
      defineReactive(obj, key)
    }
  }
}

// 创建一个Observer实例,并且能够进入Observer的初始化
function observe(value) {
  if (typeof value !== "object") {
    return
  }
  let ob
  if (typeof value.__ob__ !== "undefined") {
    ob = value.__ob__
  } else {
    ob = new Observer(value)
  }

  return ob
}
处理数组的响应式
import def from "./def"

const arrayPrototype = Array.prototype

// 以Array.prototype为原型创建arrayMethods对象

export const arrayMthods = Object.create(arrayPrototype)

console.log(arrayMthods)

const methodsName = ["push", "pop", "shift","splice","unshift","revert","sort"]

methodsName.forEach(method => {
  const original = arrayPrototype[method]

  def(
    arrayMthods,
    method,
    function () {
      //   把这个数组身上的__ob__取出来
      const ob = this.__ob__

      let inserted = []
      switch (method) {
        case "push":
        case "unshift":
          inserted = arguments
          break
        case "splice" :
            inserted = [...arguments].slice(2)
        break
      }

      if (inserted.length > 0) {
        ob.observeArray(inserted)
      }
      return original.apply(this, arguments)
    },
    false
  )
})

Wacher类
import Dep from "./Dep"

function parsePath(exp) {
  const arr = exp.split(".")

  return obj => {
    for (let i = 0; i < arr.length; i++) {
      obj = obj[i]
    }

    return obj
  }
}

export default class Watcher {
  constructor(target, exp, callback) {
    this.target = target
    // "exp  a.b.c.d"
    this.getter = parsePath(exp)

    this.callback = callback
    this.value = this.get()
  }
  update() {}
  get() {
    // 依赖收集
    Dep.target = this
    const obj = this.target
    let value

    try {
      value = this.getter(obj)
    } finally {
      Dep.target = null
    }

    return value
  }

  run() {
    this.getAndInvoke(this.callback)
  }

  getAndInvoke(cb) {
    const value = this.get()

    if (value !== this.value || typeof value == "object") {
      const oldValue = this.value

      this.value = value

      cb.call(this.target, value, oldValue)
    }
  }
}