Vue3.2变量声明ref源码分析

63 阅读2分钟

说明:我推荐直接看源码,我这个文章也是看源码进行描述的。

1. ref的变量声明vue背后做了什么?

const name = ref<string>('') // ts
const names = ref("") // js

我们尝试分析一下

  1. 首先可以确定ref是个函数,那ref的源码有可能是这样的,ref是支持默认值的
function ref (value){
    ...
}
  1. 让我们看一下源码是怎样做的?
// 源码在声明ref函数的return一个createRef,如下
function ref(value){
    return createRef(value, false)
}

3.看一下createRef这个函数是干嘛的?先看源码再说作用

function createRef(rawValue, shallow){
    if (isRef(rawValue)) { // 判断这个值有没有_isRef这个属性
         return rawValue
    }
    return new RefImpl(rawValue, shallow)
}
function isRef(r) {
    return !!(r && r.__v_isRef === true);
}
// 1. 首先判断这个值是不是已经通过ref创建过了,创建过的数据会有一个isRef = true 的属性,如果已经有这个属性直接返回这个值
// 2. 如果没有需要通过new RefImpl构造函数来包装这个值,
// 3. 其中有一个比较重要的属性就是isRef判断数据是不是用ref来创建的,并且有一些属性绑定在这个值上边
// 4. 还得判断这个数据是不是object,如果是复杂数据类型就用reactive去操作(也就是说ref可以声明复杂数据类型)
// 5. 在当前这个作用域创建这个值
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);
        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 (shared.hasChanged(newVal, this._rawValue)) {
            this._rawValue = newVal;
            this._value = this.__v_isShallow ? newVal : toReactive(newVal);
            triggerRefValue(this, newVal);// this -> 当前作用域
        }
    }
}

function triggerRefValue(ref, newVal) {
    ref = toRaw(ref);
    if (ref.dep) {
        {
            triggerEffects(ref.dep, {
                target: ref,
                type: "set" /* SET */,
                key: 'value',
                newValue: newVal
            });
        }
    }
}

总结:使用ref声明变量的的时候,vue会先分析这个有没有被声明过,如果声明过就有_isRef这个属性直接返回。如果没有_isRef这个属性就说明这个变量在当前作用域没有被声明(只有进到当前页面,这个页面的变量会被创建,加载,使用),就可以使用 new RefImpl(value)来创建新的变量,这创建的过程中会添加一下属性,并且通过 shared.isobject()判断这个属性的类型是否是数组或者对象,如果是就通过toReactive来处理类型的声明。