说明:我推荐直接看源码,我这个文章也是看源码进行描述的。
1. ref的变量声明vue背后做了什么?
const name = ref<string>('') // ts
const names = ref("") // js
我们尝试分析一下
- 首先可以确定ref是个函数,那ref的源码有可能是这样的,ref是支持默认值的
function ref (value){
...
}
- 让我们看一下源码是怎样做的?
// 源码在声明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来处理类型的声明。