用ref包装数组执行过程
// 堆代码 duidaima.com
// 用ref来包装数组 1
const list1 = ref([]);
console.log(list1);
// 创建ref 2
function ref(value) {
return createRef(value, false);
}
// 创建ref对象,判断传入的值是不是Ref对象,如果是就不需要再次包装了,直接返回
// 3
function createRef(rawValue, shallow) {
if (isRef(rawValue)) {
return rawValue;
}
return new RefImpl(rawValue, shallow);
}
// 在类的内部可以使用get和set关键字,对某个属性这种存储值函数和取值函数,
// 拦截该属性的存取行为(此时就可以做想做的事情,如,set中,就可以去修改
// 视图中对用参数的数据)
// 这也是响应式的基本原理,
class RefImpl {
constructor(value, __v_isShallow) {
this.__v_isShallow = __v_isShallow;
this.dep = undefined;
this.__v_isRef = true;
this._rawValue = __v_isShallow ? value : toRaw(value);
// 4 实例化一个对象时,对对象的_value值进行赋值
this._value = __v_isShallow ? value : toReactive(value);
}
get value() {
trackRefValue(this);
return this._value;
}
set value(newVal) {
newVal = this.__v_isShallow ? newVal : toRaw(newVal);
if (hasChanged(newVal, this._rawValue)) {
this._rawValue = newVal;
this._value = this.__v_isShallow ? newVal : toReactive(newVal);
triggerRefValue(this, newVal);
}
}
}
// 此时去判断传入的数据的类型 5
// 如果是基本数据类型,那么直接返回当前值
// 如果是对象类型,则通过reactive函数对其操作
const toReactive = (value) => isObject(value) ? reactive(value) : value;
// 创建 createReactiveObject 对象
function reactive(target) {
// if trying to observe a readonly proxy, return the readonly version.
if (isReadonly(target)) {
return target;
}
return createReactiveObject(target, false, mutableHandlers, mutableCollectionHandlers, reactiveMap);
}
用reactive包装数组执行过程
const list = reactive([]);
console.log(list);
// 堆代码 duidaima.com
// 判断是否只读
function reactive(target) {
// if trying to observe a readonly proxy, return the readonly version.
if (isReadonly(target)) {
return target;
}
return createReactiveObject(target, false, mutableHandlers, mutableCollectionHandlers, reactiveMap);
}
// 创建 createReactiveObject 对象
function createReactiveObject(target, isReadonly, baseHandlers, collectionHandlers, proxyMap) {
if (!isObject(target)) {
if ((process.env.NODE_ENV !== 'production')) {
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["__v_raw" /* RAW */] &&
!(isReadonly && target["__v_isReactive" /* 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 === 0 /* INVALID */) {
return target;
}
// 通过Proxy类对target对象生成一个代理对象
const proxy = new Proxy(target, targetType === 2 /* COLLECTION */ ? collectionHandlers : baseHandlers);
proxyMap.set(target, proxy);
return proxy;
}
通过对源码的阅读,我们可以看到,通过ref方法包装获取一个响应式的对象list1,返回的是一个RefImpl类型的对象,该对象的value值的是 Proxy类型的实例化对象。通过reactive方法包装获取一个响应式对象list,返回的是一个Proxy类型的实例化对象
这两种方法都可以定义响应式数组对象,且两者的定义本质上还是 一个Proxy类型的实例化对象,但用ref包装的数组生成的响应式对象多了一层,即RefImpl类型的对象。所以定义响应式数组对象,用reactive比较合适。