我通过ChatGpt复习Vue第二天

Vue.js 响应式系统源码解析

Vue 2 响应式系统

1. 响应式数据的初始化

当创建一个 Vue 实例时,Vue 会遍历 data 对象的所有属性,并将它们转换为响应式属性。以下是关键的源码实现:

function defineReactive(obj, key, val) {
  const dep = new Dep(); // 用于收集依赖和通知变化
  let childOb = observe(val); // 递归观察子对象
  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get() {
      // 收集依赖
      if (Dep.target) {
        dep.depend();
        if (childOb) {
          childOb.dep.depend(); // 如果值是对象,也要收集依赖
        }
      }
      return val;
    },
    set(newVal) {
      if (newVal === val) return;
      val = newVal;
      childOb = observe(newVal); // 更新新值的观察
      dep.notify(); // 通知视图更新
    }
  });
}

defineReactive 函数将对象的属性 key 转换为响应式属性。
dep 是一个 Dep 实例,用于管理依赖和通知变化。
Object.defineProperty 用于定义属性的 getter 和 setter。
getter 中的 Dep.target 是当前正在计算依赖的 Watcher 实例。
setter 用于处理数据变化,并通知所有相关的 Watcher 更新视图。

2. 依赖收集 (Dep)

class Dep {
  constructor() {
    this.subs = [];
  }

  addSub(sub) {
    this.subs.push(sub);
  }

  depend() {
    if (Dep.target) {
      Dep.target.addDep(this);
    }
  }

  notify() {
    this.subs.forEach(sub => sub.update());
  }
}

Dep 类负责管理所有依赖(即 Watcher 实例)。
addSub 将 Watcher 添加到依赖列表。
depend 方法在 getter 中调用,用于收集依赖。
notify 方法在数据变化时调用,用于通知所有依赖更新视图。

3. Watcher 的实现

class Watcher {
  constructor(vm, expOrFn, cb) {
    this.vm = vm;
    this.cb = cb;
    this.expOrFn = expOrFn;
    this.deps = [];
    this.depsId = new Set();
    this.get();
  }

  get() {
    Dep.target = this;
    // 执行传入的函数来触发数据访问
    this.expOrFn.call(this.vm, this.vm);
    Dep.target = null;
  }

  addDep(dep) {
    const id = dep.id;
    if (!this.depsId.has(id)) {
      this.deps.push(dep);
      this.depsId.add(id);
      dep.addSub(this);
    }
  }

  update() {
    // 当数据变化时调用
    this.cb();
  }
}

Watcher 负责处理数据变化时的回调。
get 方法会执行传入的函数,触发数据访问并收集依赖。
addDep 将 Dep 实例添加到 Watcher 的依赖列表中。
update 方法在数据变化时被调用,用于更新视图。

4. 观察对象 (observe)

function observe(value) {
  if (!value || typeof value !== 'object') {
    return;
  }
  if (value.__ob__) {
    return value.__ob__;
  }
  return new Observer(value);
}

class Observer {
  constructor(value) {
    this.value = value;
    this.dep = new Dep();
    Object.defineProperty(value, '__ob__', {
      enumerable: false,
      configurable: false,
      value: this
    });
    if (Array.isArray(value)) {
      // 特殊处理数组
      this.observeArray(value);
    } else {
      this.walk(value);
    }
  }

  walk(obj) {
    Object.keys(obj).forEach(key => defineReactive(obj, key, obj[key]));
  }

  observeArray(items) {
    items.forEach(item => observe(item));
  }
}

observe 函数用于创建 Observer 实例。
Observer 类负责将对象的所有属性转化为响应式。
walk 方法遍历对象的属性并调用 defineReactive。
observeArray 方法专门处理数组的响应式数据。

Vue 3 响应式系统

1. 创建响应式对象

在 Vue 3 中,响应式系统通过 reactive 函数实现,底层使用 Proxy 进行数据的代理。

import { reactive, effect } from 'vue';

// 创建响应式对象
const state = reactive({
  count: 0
});

reactive 是 Vue 3 中创建响应式对象的主要方法。
它使用 Proxy 来代理对象的访问和修改操作,实现响应式功能。

2. Proxy 的实现

Vue 3 使用 Proxy 的 get 和 set 捕获器来拦截对对象的操作,实现响应式。

function createReactiveObject(target, baseHandlers) {
  return new Proxy(target, baseHandlers);
}

const baseHandlers = {
  get(target, key, receiver) {
    // 收集依赖
    const result = Reflect.get(target, key, receiver);
    track(target, key);
    return result;
  },
  set(target, key, value, receiver) {
    // 修改数据
    const result = Reflect.set(target, key, value, receiver);
    trigger(target, key);
    return result;
  }
};

createReactiveObject 函数创建一个新的 Proxy 实例。
baseHandlers 定义了 Proxy 的 get 和 set 捕获器。
get 捕获器用于拦截对对象属性的读取操作,收集依赖。
set 捕获器用于拦截对对象属性的修改操作,触发更新。

3. 收集依赖和触发更新

const targetMap = new Map();

function track(target, key) {
  let depsMap = targetMap.get(target);
  if (!depsMap) {
    targetMap.set(target, (depsMap = new Map()));
  }
  let dep = depsMap.get(key);
  if (!dep) {
    depsMap.set(key, (dep = new Set()));
  }
  dep.add(activeEffect);
}

function trigger(target, key) {
  const depsMap = targetMap.get(target);
  if (!depsMap) return;
  const dep = depsMap.get(key);
  if (dep) {
    dep.forEach(effect => effect());
  }
}

let activeEffect = null;

function effect(fn) {
  const _effect = () => {
    activeEffect = _effect;
    fn();
    activeEffect = null;
  };
  _effect();
}

track 函数用于收集依赖,它将当前活跃的 effect 函数添加到依赖集合中。
trigger 函数用于触发更新,它会通知所有依赖的 effect 函数执行。
activeEffect 记录当前活跃的 effect 函数,用于依赖收集。
effect 函数用于创建和注册副作用函数。

4. 深度响应式(嵌套对象和数组)

const baseHandlers = {
  get(target, key, receiver) {
    const result = Reflect.get(target, key, receiver);
    if (typeof result === 'object' && result !== null) {
      return reactive(result);
    }
    track(target, key);
    return result;
  }
};

get 捕获器中,如果读取的值是对象类型,递归调用 reactive 使其也变为响应式。

5. ref 和 shallowReactive

import { ref, shallowReactive } from 'vue';

// ref 用于创建基本数据类型的响应式引用
const count = ref(0);

// shallowReactive 用于创建浅响应式对象
const state = shallowReactive({
  count: 0
});

ref 用于创建基本数据类型的响应式引用,它会返回一个包含 value 属性的对象。
shallowReactive 用于创建浅响应式对象,它只会使对象的第一层属性变为响应式。

总结

Vue 3 的响应式系统相比 Vue 2 更加高效和灵活,主要通过 Proxy 实现,能够更好地处理深度嵌套的对象和数组。它通过 track 和 trigger 函数来实现依赖收集和视图更新,具有更好的性能和更简洁的 API。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值