自学内容网 自学内容网

vue/core源码中ref源码的js化

起源:

当看见reactivity文件中的ref.ts文件长达五百多的ts代码后,突发奇想想看下转化成js有多少行。

进行转化:

let shouldTrack = true; // Define shouldTrack variable
let activeEffect = null; // Define activeEffect variable

// 定义 ref 函数
function ref(value) {
  return createRef(value, false);
}

// 浅的引用 ref
function shallowRef(value) {
  return createRef(value, true);
}

// 创造 ref 函数
function createRef(rawValue, shallow) {
  // 判断 rawValue 是不是 ref 类型的
  if (isRef(rawValue)) {
    // 是的话直接 retur
    return rawValue;
  }
  // 不是的话 使用:RefImpl 将其变成ref对象后return出去
  return new RefImpl(rawValue, shallow);
}
// 定义 ref的 对象 RefImpl 类
class RefImpl {
  constructor(value, isShallow) {
    this._rawValue = isShallow ? value : toRaw(value);
    this._value = isShallow ? value : toReactive(value);
  }

  get value() {
    trackRefValue(this);
    return this._value;
  }

  set value(newVal) {
    const useDirectValue = this.__v_isShallow || isShallow(newVal) || isReadonly(newVal);
    newVal = useDirectValue ? newVal : toRaw(newVal);
    if (hasChanged(newVal, this._rawValue)) {
      this._rawValue = newVal;
      this._value = useDirectValue ? newVal : toReactive(newVal);
      triggerRefValue(this, DirtyLevels.Dirty, newVal);
    }
  }
}

function trackRefValue(ref) {
  if (shouldTrack && activeEffect) {
    ref = toRaw(ref);
    trackEffect(
      activeEffect,
      (ref.dep ??= createDep(
        () => (ref.dep = undefined),
        ref instanceof ComputedRefImpl ? ref : undefined,
      )),
      __DEV__
        ? {
            target: ref,
            type: TrackOpTypes.GET,
            key: 'value',
          }
        : void 0
    );
  }
}

function triggerRefValue(ref, dirtyLevel = DirtyLevels.Dirty, newVal) {
  ref = toRaw(ref);
  const dep = ref.dep;
  if (dep) {
    triggerEffects(
      dep,
      dirtyLevel,
      __DEV__
        ? {
            target: ref,
            type: TriggerOpTypes.SET,
            key: 'value',
            newValue: newVal,
          }
        : void 0
    );
  }
}
// 判断是不是ref
function isRef(r) {
  return !!(r && r.__v_isRef === true);
}

function toRaw(observed) {
  return observed;
}

function toReactive(value) {
  return value;
}

let result = ref(0);
console.log(result);

转化完毕,相信看过源码的小伙伴一经发现,转化前的代码非常臃肿且难以阅读,转化后的代码轻便易于阅读,且能快速在浏览器的控制台调试和实现ref的功能。

最后我们通过打印result可以看到输出了一个RefImpl对象,之后我们通过打印result.value即可获得我们当初传给ref的0

经过测试,发现输出的颜色很淡的values是class类中的get values方法

当传进_value的值的时候,因为构造函数中的get values方法是return的,所以在最后的console中点开values是可以看见: "这里是_values"输出的

将get values函数中return改为console后,打印出来的values就是undefined了,因为没有向外return了

同理,这时候想要学习vue3,通过john.values就可以打印出: "这里是_value"了.

但是感觉下面的_value和value是一个东西,可以用_value统一起来方便看:

class RefImpl {
  constructor(value, isShallow) {
    this._rawValue = isShallow ? value : toRaw(value);
    this._value = isShallow ? value : toReactive(value);
  }

  get value() {
    trackRefValue(this);
    return this._value;
  }

  set value(newVal) {
    const useDirectValue = this.__v_isShallow || isShallow(newVal) || isReadonly(newVal);
    newVal = useDirectValue ? newVal : toRaw(newVal);
    if (hasChanged(newVal, this._rawValue)) {
      this._rawValue = newVal;
      this._value = useDirectValue ? newVal : toReactive(newVal);
      triggerRefValue(this, DirtyLevels.Dirty, newVal);
    }
  }
}

上述: get value方法中return的this._value就是constructor中穿进去的value,统一更方便看.


原文地址:https://blog.csdn.net/kuang_nu/article/details/139087553

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!