上一篇文章我们讲了reactive
的源码解析,相信大家已经对其已经有了深刻的理解,那么ref
和它有什么不同呢?
这一篇文章,我们就来了解一下ref
是如何实现的。上一篇文章说到,reactive
是用于让对象变成响应式,那么原始类型怎么办呢,使用ref
实现吗,,没错,正如大家所想的那样,原始类型的响应式实现正是依靠ref
,并且ref
功能更为强大,它还能使对象变成响应式,也就是说,它涵盖了reactive
的功能。
引入
import { ref } from 'vue';
const count = ref(1)
console.log(count.value); // 1
上面的打印结果是1,相信大家都能接受,但是为什么count
后面要接.value
呢。
首先呢,ref
返回的是一个对象,访问对象里面的属性使用.xxx
没毛病吧,至于为什么是.value
,咱来看看这个对象里面有什么:
console.log(count.value);
大家也看到了,里面封装的就是value
,所以合情合理。那么究竟是怎么实现的呢?
实现一个简单的ref
我们已经知道reactive
实现的核心就是Proxy
,那么ref
肯定是不能这样的,因为Proxy
只能接受对象作为为参数。所以我们只能自己打造一个代理函数来实现响应式。那应该怎么做呢?首先我们得知道
- 当数据是对象时,继续使用Proxy代理
- 在函数内部我们也使用一个
this.__V_isRef = true
属性来记录是否已经是响应式 - 使用
this._value = target
存放传进来的数据 get value() {}
用于获取值 相当于Proxy
中的get
set value(newVal) {}
用于修改值 相当于Proxy
中的set
class RefImal { // 创建一个构造函数,用于将val变成响应式
constructor(target) {
this.__V_isRef = true // 给已经代理过的target打上标记,用于判断是否已经是响应式
if(typeof target !== 'object' || target === null) {
this._value = target
} else { // 对象使用Proxy代理
this._value = new Proxy(target,{
get: (target,key,receiver) => {
const res = Reflect.get(target,key,receiver) // 获取值
// 收集副作用函数(即用到了这个属性的函数)
track(target,key) // 用于收集副作用函数,详细代码参考上一篇reactive的文章
return res
},
set: (target,key,value,receiver) => {
Reflect.set(target,key,value,receiver) // 修改值
// 值变更时触发副作用函数
trigger(target,key) // 用于触发副作用函数,详细代码参考上一篇reactive的文章
return true
}
})
}
}
// 获取值
get value() {
const res = this._value
if(typeof res === 'object' && res !== null) {
return res // 是对象,已经收集过副作用函数,直接返回
}
track(this, 'value')
return res
}
// 修改值
set value(newVal) {
this._value = newVal
trigger(this, 'value')
return true
}
}
上面的是核心,接下来就是主体部分,这个比较简单,和reactive
差不多
export function ref(target) {
// 判断是否已经是响应式
if(target.__V_isRef){
return
}
// 将val变成响应式
const refimal = new RefImal(target)
// 返回val
return refimal
}
这样我们就实现了一个简单的ref
,是不是很简单,接下来我们来说说它们的区别。
区别
- 功能方面:
ref
的功能显然是比reactive
强大的,它不仅可以使原始类型变成响应式,还能使引用类型变成响应式。reactive
只能使对象变成响应式。
- 运用:
ref
代理的数据在使用时要加上xxx.value
,如果代理的数据是对象还要加上key
,如xxx.value.key
reactive
代理的数据使用时只需要xxx.key
- 所以原始类型的代理我们通常使用
ref
,对象通常使用reactive
,这就是为什么ref
明明涵盖了reactive
的功能,还要打造一个reactive
假如您也和我一样,在准备春招。欢迎加我微信shunwuyu
,这里有几十位一心去大厂的友友可以相互鼓励,分享信息,模拟面试,共读源码,齐刷算法,手撕面经。来吧,友友们!
原文链接:https://juejin.cn/post/7338314540302532647 作者:小白234