源码是ts编写的,这里部分简化成js便于阅读
function ref(value) {
return createRef(value, false)
}
function createRef(rawValue, shallow) { //shallow是否是浅层定义数据,用于区别ref和shallowRef
if (isRef(rawValue)) {//如果已经是ref直接返回源数据
return rawValue
}
return new RefImpl(rawValue, shallow)
}
class RefImpl<T> {
private _value: T
private _rawValue: T
public dep?: Dep = undefined
public readonly __v_isRef = true
constructor(
value: T,//第一个参数value:传入的源数据
public readonly __v_isShallow: boolean //第二个参数__v_isShallow:是否是浅层次响应的属性
) {
this._rawValue = __v_isShallow ? value : toRaw(value)
this._value = __v_isShallow ? value : toReactive(value)//初始化数据如果是已经包装过的__v_isShallow就是true,否则通过toReactive包装传入的参数
}
get value() {
trackRefValue(this) //依赖收集
return this._value
}
set value(newVal) {
const useDirectValue = this.__v_isShallow || isShallow(newVal) || isReadonly(newVal)//判断是否已经是vue包装过的对象
newVal = useDirectValue ? newVal : toRaw(newVal)
if (hasChanged(newVal, this._rawValue)) {
this._rawValue = newVal
this._value = useDirectValue ? newVal : toReactive(newVal)//如果已经包装过返回源数据,否则通过toReactive包装传入的参数
triggerRefValue(this, newVal)//触发响应式更新
}
}
}
toReactive = (value) => isObject(value) ? reactive(value) : value //基本数据类型通过class类依赖收集触发更新,引用数据类型通过Proxy代理实现
isObject = (val) => val !== null && typeof val === 'object' //上面用到的函数:判断是否是一个对象
//reactive()函数调用createReactiveObject函数(内部通过new Proxy())创建响应式数据,如下:
function createReactiveObject(
target: Target,
isReadonly: boolean,
baseHandlers: ProxyHandler<any>,
collectionHandlers: ProxyHandler<any>,
proxyMap: WeakMap<Target, any>
) {
if (!isObject(target)) { //如果不是对象直接返回源数据,所以必须传入对象才有效
if (__DEV__) {
console.warn(`value cannot be made reactive: ${String(target)}`)
}
return target
}
// target is already a Proxy, return it.
// exception: calling readonly() on a reactive object
if (
target[ReactiveFlags.RAW] &&
!(isReadonly && target[ReactiveFlags.IS_REACTIVE])
) {
return target
}
// target already has corresponding Proxy
const existingProxy = proxyMap.get(target)
if (existingProxy) {
return existingProxy
}
// only specific value types can be observed.
const targetType = getTargetType(target)
if (targetType === TargetType.INVALID) {
return target
}
const proxy = new Proxy(//创建Proxy代理
target,
targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers
)
proxyMap.set(target, proxy)
return proxy
}
总结:
ref() 函数通过调用new RefImpl(rawValue, shallow)这个class类来包装数据,内部有value属性(可读get通过trackRefValue收集依赖;可写set通过triggerRefValue更新依赖), 传入的值会调用toReactive函数进行封装.
toReactive = (value) => isObject(value) ? reactive(value) : value
isObject = (val) => val !== null && typeof val === 'object'
reactive()函数调用createReactiveObject函数(内部通过new Proxy())创建响应式数据
**ref:**定义基本数据类型通过class类中的value属性依赖收集触发更新;定义引用数据类型会调用reactive()实现数据代理
**reactive:**只用于定义引用数据类型,通过Proxy代理实现
附源码地址https://github.com/vuejs/core/tree/v3.3.4/packages/reactivity/src