Vue数据响应式原理实例代码分析

发布时间:2022-10-24 14:11:07 作者:iii
来源:亿速云 阅读:137

Vue数据响应式原理实例代码分析

引言

Vue.js 是一个渐进式 JavaScript 框架,其核心特性之一就是数据响应式系统。Vue 的数据响应式系统使得开发者可以声明式地描述数据与视图之间的关系,当数据发生变化时,视图会自动更新。本文将深入探讨 Vue 数据响应式原理,并通过实例代码分析其实现机制。

1. Vue 数据响应式的基本概念

1.1 什么是数据响应式

数据响应式是指当数据发生变化时,依赖该数据的视图或其他逻辑会自动更新。Vue 通过数据劫持和依赖收集的方式实现了数据响应式。

1.2 Vue 数据响应式的核心

Vue 数据响应式的核心是 Object.definePropertyProxy,Vue 2.x 使用 Object.defineProperty,而 Vue 3.x 则使用 Proxy。本文将主要基于 Vue 2.x 的 Object.defineProperty 进行讲解。

2. Vue 数据响应式的实现原理

2.1 数据劫持

Vue 通过 Object.defineProperty 对数据进行劫持,即在数据对象的属性上定义 gettersetter,从而在读取和修改数据时能够触发相应的逻辑。

function defineReactive(obj, key, val) {
  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function reactiveGetter() {
      console.log(`get ${key}: ${val}`);
      return val;
    },
    set: function reactiveSetter(newVal) {
      console.log(`set ${key}: ${newVal}`);
      val = newVal;
    }
  });
}

const data = { name: 'Vue' };
defineReactive(data, 'name', data.name);

data.name; // get name: Vue
data.name = 'React'; // set name: React

2.2 依赖收集

Vue 在 getter 中收集依赖,在 setter 中触发依赖更新。依赖是指那些依赖于该数据的视图或计算属性。

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

  depend() {
    if (Dep.target) {
      this.subscribers.push(Dep.target);
    }
  }

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

Dep.target = null;

function defineReactive(obj, key, val) {
  const dep = new Dep();

  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function reactiveGetter() {
      dep.depend();
      return val;
    },
    set: function reactiveSetter(newVal) {
      val = newVal;
      dep.notify();
    }
  });
}

const data = { name: 'Vue' };
defineReactive(data, 'name', data.name);

function watcher(fn) {
  Dep.target = fn;
  fn();
  Dep.target = null;
}

watcher(() => {
  console.log(`name changed: ${data.name}`);
});

data.name = 'React'; // name changed: React

2.3 观察者模式

Vue 的依赖收集和触发更新机制基于观察者模式。Dep 类是依赖收集器,Watcher 类是观察者,当数据发生变化时,Dep 会通知所有 Watcher 进行更新。

3. Vue 数据响应式的实例分析

3.1 简单的响应式系统

下面是一个简单的响应式系统实现,模拟了 Vue 的数据响应式机制。

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

  depend() {
    if (Dep.target) {
      this.subscribers.push(Dep.target);
    }
  }

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

Dep.target = null;

function defineReactive(obj, key, val) {
  const dep = new Dep();

  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function reactiveGetter() {
      dep.depend();
      return val;
    },
    set: function reactiveSetter(newVal) {
      val = newVal;
      dep.notify();
    }
  });
}

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

function watcher(fn) {
  Dep.target = fn;
  fn();
  Dep.target = null;
}

const data = { name: 'Vue', age: 3 };
observe(data);

watcher(() => {
  console.log(`name changed: ${data.name}`);
});

watcher(() => {
  console.log(`age changed: ${data.age}`);
});

data.name = 'React'; // name changed: React
data.age = 4; // age changed: 4

3.2 嵌套对象的响应式处理

Vue 不仅能够处理简单的对象属性,还能够处理嵌套对象的响应式。

function observe(obj) {
  if (typeof obj !== 'object' || obj === null) {
    return;
  }

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

function defineReactive(obj, key, val) {
  observe(val); // 递归处理嵌套对象

  const dep = new Dep();

  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function reactiveGetter() {
      dep.depend();
      return val;
    },
    set: function reactiveSetter(newVal) {
      if (newVal === val) return;
      val = newVal;
      observe(newVal); // 对新值进行响应式处理
      dep.notify();
    }
  });
}

const data = { user: { name: 'Vue', age: 3 } };
observe(data);

watcher(() => {
  console.log(`user.name changed: ${data.user.name}`);
});

data.user.name = 'React'; // user.name changed: React

3.3 数组的响应式处理

Vue 对数组的处理与对象略有不同,Vue 通过重写数组的变异方法(如 pushpopshift 等)来实现数组的响应式。

const arrayProto = Array.prototype;
const arrayMethods = Object.create(arrayProto);

['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(method => {
  const original = arrayProto[method];
  Object.defineProperty(arrayMethods, method, {
    value: function mutator(...args) {
      const result = original.apply(this, args);
      const ob = this.__ob__;
      ob.dep.notify();
      return result;
    },
    enumerable: false,
    writable: true,
    configurable: true
  });
});

function observe(obj) {
  if (typeof obj !== 'object' || obj === null) {
    return;
  }

  if (Array.isArray(obj)) {
    obj.__proto__ = arrayMethods;
    obj.forEach(item => observe(item));
  } else {
    Object.keys(obj).forEach(key => {
      defineReactive(obj, key, obj[key]);
    });
  }
}

const data = { items: ['Vue', 'React'] };
observe(data);

watcher(() => {
  console.log(`items changed: ${data.items.join(', ')}`);
});

data.items.push('Angular'); // items changed: Vue, React, Angular

4. Vue 3.x 的 Proxy 实现

Vue 3.x 使用 Proxy 替代 Object.defineProperty 来实现数据响应式。Proxy 提供了更强大的拦截能力,能够更好地处理数组和嵌套对象。

function reactive(obj) {
  const handler = {
    get(target, key, receiver) {
      console.log(`get ${key}`);
      return Reflect.get(target, key, receiver);
    },
    set(target, key, value, receiver) {
      console.log(`set ${key}: ${value}`);
      return Reflect.set(target, key, value, receiver);
    }
  };

  return new Proxy(obj, handler);
}

const data = reactive({ name: 'Vue' });

data.name; // get name
data.name = 'React'; // set name: React

5. 总结

Vue 的数据响应式系统是其核心特性之一,通过数据劫持和依赖收集,Vue 能够自动追踪数据变化并更新视图。Vue 2.x 使用 Object.defineProperty 实现数据响应式,而 Vue 3.x 则使用 Proxy 提供了更强大的拦截能力。通过本文的实例代码分析,我们可以更深入地理解 Vue 数据响应式的实现原理。

6. 参考资料


通过本文的分析,我们不仅了解了 Vue 数据响应式的基本概念和实现原理,还通过实例代码深入探讨了其实现细节。希望本文能够帮助读者更好地理解 Vue 的数据响应式系统,并在实际开发中加以应用。

推荐阅读:
  1. vue.js响应式原理
  2. vue数据响应式的原理是什么

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

vue

上一篇:如何用vue实现组件间参数传递

下一篇:如何使用vue实现一个toast弹窗组件

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》