vue2.x响应式原理实现-代码干货带你手写响应式

vue作为现在热门的三大框架之一,相信大部分前端开发者都能够熟练的使用vue,但是能够深入了解其原理的可能并不多,很多人都知道vue响应式是通过difineProperty来实现的,相信随便百度一下,相关的面试题及答案一大堆,你知道是通过defineProperty重写get,set方法实现的,可是你有真正的了解过吗?好了,上干货!!!

实现对象的监听

此时能够监听对象数据的变化,还不能监听数组的变化。为什么?因为它本身就不可以呀,那你可能要问了,明明vue的数组,,通过push、pop、shift等等方法改变数组是监听到变化的呀。没错,vue是可以监听到,那是因为重写了数组push、pop、unshift、shift等方法,别急,后面慢慢道来。
(在代码中我会写清楚注释,如果有不理解的地方、或者不对的地方,欢迎留言指出)

function observe(target) {
  if (typeof target !== 'object' || target === null) {
    return
  }

  for(let key in target) {
    defineReactive(target, key, target[key])
  }
}

function defineReactive(target, key, value) {
  console.log(target, key, value)
  Object.defineProperty(target, key, {
    get (key) {
      return value
    },
    set (newValue) {
      if (value !== newValue) {
        observe(value) // 新赋值的数据可能是对象,数组等,此处需要处理新的数据
        const oldValue = value //对象无法知道旧的数据,因为是引用类型
        value = newValue
        updateData(value, oldValue)
      }
    }
  })
}

function updateData(value, oldValue) {
  // 监听到了数据变化,更新视图
  console.log('监听到了数据变化,更新视图 => ', value, oldValue)
}


let obj1 = {
  a: 111,
  c: 'djklf',
  d: {
    d1: 123
  },
  // arr: ['122', 453, 'kk']
}
observe(obj1)

console.log(obj1.a)

obj1.a = 'ff'
监听数组的变化

这里涉及到一些原型链的知识点,不做讲解,如果有需要的话留言哦

const arrProperty = Array.prototype
const arrProto = Object.create(arrProperty)

// 此处只重写了push、pop、unshift、shift方法,
// vue支持的方法为:push、pop、shift、unshift、splice、sort、reverse
;['push', 'pop', 'unshift', 'shift'].forEach(methodName => {
  arrProto[methodName] = function () {
    arrProperty[methodName].call(this, ...arguments)
    updateData('数组改变','数组改变') // 数据更新
  }
})

当数据为数组是改变它的__proto__

if (target instanceof Arrary) {
	target.__proto__ = arrProto
}

完整代码


const arrProperty = Array.prototype
const arrProto = Object.create(arrProperty);
['push', 'pop', 'unshift', 'shift'].forEach(methodName => {
  arrProto[methodName] = function () {
    arrProperty[methodName].call(this, ...arguments)
    updateData(1,1) // 监听到数据更新
  }
})

function observe(target) {
  if (typeof target !== 'object' || target === null) {
    return
  }

  if (target instanceof Array) {
    target.__proto__ = arrProto
  }

  for(let key in target) {
    defineReactive(target, key, target[key])
  }
}

function defineReactive(target, key, value) {
  observe(value)
  Object.defineProperty(target, key, {
    get () {
      return value
    },
    set (newValue) {
      if (value !== newValue) {
        observe(value) // 新赋值的数据可能是对象,数组等,此处需要处理新的数据
        const oldValue = value
        value = newValue
        updateData(value, oldValue)
      }
    }
  })
}

function updateData(value, oldValue) {
  // 监听到了数据变化,更新视图
  console.log('监听到了数据变化,更新视图 => ', value, oldValue)
}

// 测试数据
let obj1 = {
  a: 111,
  c: 'djklf',
  d: {
    d1: 123
  },
  arr: ['122', 453, 'kk']
}
observe(obj1)


// 1秒后改变数据
setTimeout (() => {
  obj1.a = '1111'
  obj1.d.d1 = 'ff'
  obj1.c = {
    c1: 'fdf',
    c2: 1324
  }

  obj1.c.c1 = 222
  obj1.arr.push('ff')
  console.log(obj1.arr)
}, 1000)

总结

通过上面相信已经懂了响应式原理的实现了吧,所以我们能得出以下结论:

  1. 在data里,不要把对象定义的太深,循环遍历data里的数据做处理是需要时间的!!!
  2. 不需要响应式的不要定义在data里!!!可以定义在created中
  3. 数组的响应只能通过上面重写过的几个方法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值