在 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 可为函数,也可为对象。

  1. getterOrOptions 可以为函数相当于 getter 函数, 从 getter 返回的值返回一个不变的响应式 ref 对象。 类型声明 中对于这种方式的定义是read-only。
  2. getterOrOptions 也可以使用具有 get 和 set 函数的对象来创建可写的 ref 对象。 类型声明 中对于这种方式的定义是 writable。

总结:

当 getterOrOptions 为函数,ComputedRefImpl.__v_isReadonly = true,表示此ComputedRefImpl对象只读不可写。

当 getterOrOptions 具有 get 和 set 函数的对象,ComputedRefImpl.__v_isReadonly = false,表示此ComputedRefImpl对象可读可写。

源码中还包含:"effect " 、"track"、"trigger"、"toRaw" 函数,等我们用到了在专门的开篇进行讲解。

Logo

前往低代码交流专区

更多推荐