vue 2 简化版数据响应原理

// vue2对象响应式原理:Object.defineProperty()
// vue2数组响应式原理:覆盖可以修改数组7个方法
// 从数组原型中获取这7个方法,并覆盖为可以发送更新通知的函数实现
const originalProto = Array.prototype
const arrayProto = Object.create(originalProto)
;['push', 'pop', 'shift', 'unshift', 'splice', 'reverse', 'sort'].forEach(
  method => {
    arrayProto[method] = function() {
      // 做之前的事情
      originalProto[method].apply(this, arguments)

      // 通知更新
      notifyUpdate()
    }
  }
)

const isObject=(obj)=>{
  return obj !== null && typeof obj === 'object'
}
// 思想:递归遍历传入obj,定义每个属性的拦截
function observe(obj) {
  if (!isObject(obj)) {
    return obj
  }

  // 判断类型:如果是数组则替换它的原型
  if (Array.isArray(obj)) {
    Object.setPrototypeOf(obj, arrayProto)
  } else {
    const keys = Object.keys(obj)
    for (let index = 0; index < keys.length; index++) {
      const key = keys[index]
      // 对obj每个key执行拦截
      defineReactive(obj, key, obj[key])
    }
  }
}

// 具体定义指定的key拦截器
function defineReactive(obj, key, val) {
  // 递归遍历
  observe(val)

  // val实际上是一个闭包
  Object.defineProperty(obj, key, {
    get() {
      return val
    },
    set(newVal) {
      if (newVal !== val) {
        // val可能是对象
        observe(newVal)
        notifyUpdate()
        val = newVal
      }
    }
  })
}

function notifyUpdate() {
  console.log('页面更新!')
}

const data = { foo: 'foo', bar: { a: 1 }, tua: [1, 2, 3] }
observe(data)
// 1.普通更新
// data.foo = 'foooooooo'
// 2.嵌套属性更新
// data.bar.a = 10
// data.dong = 'lalala' // no ok
// 3.赋值是对象
// data.bar = {a:10}
// 4.数组
// data.tua.push(4)


// 问题分析:
// 1.需要响应化的数据较大,递归遍历性能不好、消耗较大
// 2.新增或删除属性无法监听
// 3.数组响应化需要额外实现
// 4.修改语法有限制

  

posted @ 2021-04-11 14:21  a权  阅读(69)  评论(0编辑  收藏  举报
Top