Vue3 中的 getter 和 setter 源码简解

微信扫一扫,分享到朋友圈

Vue3 中的 getter 和 setter 源码简解

vue3
中的所有 getter
都源自于一个名为 createGetter
的函数,下面试该函数的源代码

function createGetter(isReadonly = false, shallow = false) {
return function get(target: object, key: string | symbol, receiver: object) {
if (key === ReactiveFlags.IS_REACTIVE) {
return !isReadonly
} else if (key === ReactiveFlags.IS_READONLY) {
return isReadonly
} else if (
key === ReactiveFlags.RAW &&
receiver ===
(isReadonly
? (target as any)[ReactiveFlags.READONLY]
: (target as any)[ReactiveFlags.REACTIVE])
) {
return target
}
const targetIsArray = isArray(target)
if (targetIsArray && hasOwn(arrayInstrumentations, key)) {
return Reflect.get(arrayInstrumentations, key, receiver)
}
const res = Reflect.get(target, key, receiver)
if (
isSymbol(key)
? builtInSymbols.has(key)
: key === `__proto__` || key === `__v_isRef`
) {
return res
}
if (!isReadonly) {
track(target, TrackOpTypes.GET, key)
}
if (shallow) {
return res
}
if (isRef(res)) {
// ref unwrapping, only for Objects, not for Arrays.
return targetIsArray ? res : res.value
}
if (isObject(res)) {
// Convert returned value into a proxy as well. we do the isObject check
// here to avoid invalid value warning. Also need to lazy access readonly
// and reactive here to avoid circular dependency.
return isReadonly ? readonly(res) : reactive(res)
}
return res
}
}
复制代码

这个函数对输入的数据的处理流程很清晰,基本是从上到下的流程函数,下面是简要分析:

第一步

接收 isReadonly
(只读) 和 shallow
(浅转换为 Reactive—> shallowReactive)两个参数。参数表示生成不同类的 getter

第二步

接下来是一系列的判断输入,返回对应的值。

获取当前 target 的类型

开始的判断是关于类型的判断( ReactiveFlags.IS_REACTIVE
[响应式数据] 和 ReactiveFlags.IS_READONLY
[只读数据])。

获取源对象

接下来是获取源对象,也就是调用 toRaw()
方法时需要进行的判断,获取的值是转换响应式之前的源对象。

toRow
源码和详解

export function toRaw(observed) {
return (
(observed && toRaw((observed as Target)[ReactiveFlags.RAW])) || observed
)
}
复制代码

toRaw
是一个简单的迭代函数,直到传入的对象不存在 ReactiveFlags.RAW
为止,就获取到了想要的源 object
。其实这里只需要直到,一般情况下 proxy
handler
get
函数的参数 target
指的就是 proxy
的第一个参数,所以上面的 createGetter
的判断是 获取 ReactiveFlags.RAW
时直接返回 target

第三步

关于数组的几个特殊方法的处理

具体的代码分析看这里

第四步

接下来是一系列的判断代码。这一系列代码都是常规的获取 key
对应的值的判断。

使用

const res = Reflect.get(target, key, receiver)
复制代码

去获取对应 key
的值。

然后是

isSymbol(key)
? builtInSymbols.has(key)
: key === `__proto__` || key === `__v_isRef`
复制代码

这个判断是当 key 是 Symbol
的某个自有属性,或者是获取 __proto
(原型) 和 __v_isRef
(Ref 数据,获取这个属性可能是在判断输入的数据是否是 Ref
数据) 对应的值。

接下来的这段代码

if (!isReadonly) {
track(target, TrackOpTypes.GET, key)
}
if (shallow) {
return res
}
if (isRef(res)) {
return targetIsArray ? res : res.value
}
if (isObject(res)) {
return isReadonly ? readonly(res) : reactive(res)
}
复制代码

上面的代码相对来说很常规,当获取的是非 readOnly
的数据时进行追踪,然后根据数据的类型去返回对应的响应式的值。

菜鸡小结

总体来说,整个 get
的过程就是针对行的处理了几个特殊属性,漏下来的属性就按照常规属性处理,直接返回判断结果。

微信扫一扫,分享到朋友圈

Vue3 中的 getter 和 setter 源码简解

Vue created 中的异步请求的影响分析

上一篇

改造wangEditor成react组件

下一篇

你也可能喜欢

Vue3 中的 getter 和 setter 源码简解

长按储存图像,分享给朋友