Vue.set原理

let data = {
	a:{
		b:1
	}
}

经过new Observer(data)后变成了:
%%%%%%%%%%%%%%%%%%%%%%%%
let data = {
	a:{
		b: 1,
		__ob__ : {value,dep,vmCount}
	},
	__ob__: {value,dep,vmCount}
}

我们一步一步来看看这个过程是怎么发生的。

step1

首先

observe(data)
function observe(value){
	let ob = new Observer(value)
	return ob
}

step2

实际就是

ob = new Observer(data)
// ob 是构造函数的实例

它做了两件事,
第一件:给data定义了一个__ob__属性赋了三个属性

// new Observer(data)
class Observer{
	constructor(value){
		// 给value定义一个 __ob__ 属性,并且 value.__ob__ === this(this 就是ob)
		def(value,'__ob__', this)
	}
}

第二件:给ob赋了三个属性

ob :{
	value: data,
	dep,
	vmCount
}

那么根绝第一步,我们可以推导出来
data:{
	a:{
		b
	},
	__ob__ :  ob
}

总结: 每个对象都有一个 __ob__ 属性, 指向他自己的Observer实例。

第三件事:遍历data的所有属性,调用defineReactive
defineReactive(a)

   let childOb = observe(a)
   // 给a设置getter和setter 
   // 在getter/setter中通过闭包引用 childOb
   // 我们从observe的返回值可知,observe返回的是一个Observer实例
   // Observer实例有value和dep等属性, 也就是说childOb有value 和 dep等属性,并且 value的值就是a。

总之说, 对于属性a来说,a的getter/setter通过闭包引用了childOb, 而childOb === data.a.__ob__

childOb.depend()其实就是data.a.__ob__.depend()
这告诉我们,当a收集依赖时,它不仅会把观察者塞到自己闭包引用的dep筐里面去,同时还会把这个观察者塞到 a.__ob__.dep筐里去。

vue 这么做的目的是什么?
第一个筐 dep.depend()很好理解,就是我们熟知的收集依赖,当属性值被修改时触发。

第二个筐 a.__ob.__depend()收集的依赖的触发时机是在使用$setVue.set()给对象添加新属性时触发。

这是因为在没有proxy之前,vue没办法拦截到给对象添加属性的操作(vue2的源码中都是要先遍历所有属性,再给属性设置会响应式。后来添加的属性无法设置)。所以vue才提供了$set和Vue.set等方法让我们有能力给对象添加属性的同时触发依赖。

如何做到的呢?

Vue.set = function(obj,key,val){
	defineReactive(obj, key,val)
	obj.__ob__.dep.notify()
}

当我们使用

Vue.set(data.a, 'c',1)

上述代码能够触发依赖,是因为Vue.set函数中触发了
data.a.__ob__.dep这个筐里的依赖。

所以,__ob__属性以及__ob__.dep的主要作用是为了添加、删除属性时有能力触发依赖。

或许你还是不太明白,为什么是obj.__ob__.dep.notify而不是obj.dep.notify()

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值