在 Vue3 reactive 函数出现了 target.__v_isReadonly 这是什么意思呢?
function reactive(target) {
// if trying to observe a readonly proxy, return the readonly version.
if (target && target["__v_isReadonly" /* IS_READONLY */]) {
return target;
}
return createReactiveObject(target, false, mutableHandlers, mutableCollectionHandlers);
}
要理解__v_isReadonly 先要了解计算属性 computed ,没错__v_isReadonly 是相关"计算属性"才有的property。
官网介绍 computed :
使用 getter 函数,并为从 getter 返回的值返回一个不变的响应式ref对象。
const count = ref(1)
const plusOne = computed(() => count.value + 1)
console.log(plusOne.value) // 2
plusOne.value++ // error
或者,它可以使用具有 get 和 set 函数的对象来创建可写的 ref 对象。
const count = ref(1)
const plusOne = computed({
get: () => count.value + 1,
set: val => {
count.value = val - 1
}
})
plusOne.value = 1
console.log(count.value) // 0
类型声明:
// read-only
function computed<T>(getter: () => T): Readonly<Ref<Readonly<T>>>
// writable
function computed<T>(options: { get: () => T; set: (value: T) => void }): Ref<T>
写个实例代码:
export default {
setup() {
const count = ref(1);
const plusOne = computed(() => count.value + 1)
console.log(plusOne)
return {
plusOne
}
}
}
//控制台输出
ComputedRefImpl{effect: ƒ(){}, __v_isReadonly:true, __v_isRef:true, _dirty:true, _setter()=>{}}
由此可见,调用 computed 返回的是 ComputedRefImpl 实例,ComputedRefImpl 类中定义了实例的__v_isReadonly 属性值。
上 ComputedRefImpl 源码:
class ComputedRefImpl {
constructor(getter, _setter, isReadonly) {
this._setter = _setter;
this._dirty = true;
this.__v_isRef = true;
this.effect = effect(getter, {
lazy: true,
scheduler: () => {
if (!this._dirty) {
this._dirty = true;
trigger(toRaw(this), "set" /* SET */ , 'value');
}
}
});
this["__v_isReadonly" /* IS_READONLY */ ] = isReadonly;
}
get value() {
if (this._dirty) {
this._value = this.effect();
this._dirty = false;
}
track(toRaw(this), "get" /* GET */ , 'value');
return this._value;
}
set value(newValue) {
this._setter(newValue);
}
}
function computed(getterOrOptions) {
let getter;
let setter;
if (isFunction(getterOrOptions)) {
getter = getterOrOptions;
setter = () => {
console.warn('Write operation failed: computed value is readonly');
};
} else {
getter = getterOrOptions.get;
setter = getterOrOptions.set;
}
return new ComputedRefImpl(getter, setter, isFunction(getterOrOptions) || !getterOrOptions.set);
}
computed 还是很简单,获取你调用时传过来的参数。 getterOrOptions 可为函数,也可为对象。
- getterOrOptions 可以为函数相当于 getter 函数, 从 getter 返回的值返回一个不变的响应式 ref 对象。 类型声明 中对于这种方式的定义是read-only。
- getterOrOptions 也可以使用具有 get 和 set 函数的对象来创建可写的 ref 对象。 类型声明 中对于这种方式的定义是 writable。
总结:
当 getterOrOptions 为函数,ComputedRefImpl.__v_isReadonly = true,表示此ComputedRefImpl对象只读不可写。
当 getterOrOptions 具有 get 和 set 函数的对象,ComputedRefImpl.__v_isReadonly = false,表示此ComputedRefImpl对象可读可写。
源码中还包含:"effect " 、"track"、"trigger"、"toRaw" 函数,等我们用到了在专门的开篇进行讲解。