Maison > interface Web > Voir.js > Quelle est la différence entre Vue2 et Vue3 en termes de réactivité ? Comparaison simple

Quelle est la différence entre Vue2 et Vue3 en termes de réactivité ? Comparaison simple

青灯夜游
Libérer: 2022-07-04 21:00:48
avant
4494 Les gens l'ont consulté

Quelle est la différence entre Vue2 et Vue3 en termes de réactivité ? L'article suivant vous présentera la différence entre la réactivité de Vue2 et Vue3. J'espère qu'il vous sera utile !

Quelle est la différence entre Vue2 et Vue3 en termes de réactivité ? Comparaison simple

Pour la première fois, vous devez d'abord comprendre le principe et le processus de réactivité avant de pouvoir aller plus loin : du superficiel au profond est la voie à suivre. (Partage vidéo d'apprentissage : tutoriel vidéo vuejs)

Quelle est la différence entre Vue2 et Vue3 en termes de réactivité ? Comparaison simple

Ce genre d'image décrit clairement le principe responsive : chaque composant va générer une fonction de rendu (fonction de rendu), La fonction de rendu générera un vnode (DOM virtuel) Lorsque la fonction de rendu est exécutée, le getter dans data sera déclenché. quelle variable de données est déclenchée par les données, quelle variable sera observée) Plus tard, vous devrez vérifier si cette variable a été observée en raison de dépendances précédentes. Si c'est le cas, cela déclenchera setter pour modifier les données. Dans le cas contraire, l'opération de surveillance sera effectuée directement. S'il est déterminé qu'il a été ré-observé en tant que dépendance auparavant, effectuez l'opération de re-rendu re-render et effectuez l'opération pacth. L’utilisation de principes réactifs peut obtenir un meilleur rendu des données. render函数(渲染函数),而render函数又会生成一个vnode(虚拟DOM),当执行render函数的时候会触发data里面getter,触发的时候产生依赖(在data触发到哪个数据的变量,就会将哪个变量观察起来)后面需要查看这个变量是否是之前依赖而被观察起来的,如果是会触发setter进行数据修改,如果不是,会直接进行监听操作。如果确定是之前作为依赖被重新观察起来的,那就执行 re-render 重新渲染操作,并且进行pacth操作。使用响应式原理能达到更好的数据渲染作用。

Vue2.x的响应式

Vue2中通过 Object.defineProperty 实现数据劫持,使得数据实现响应式更新。Object.defineProperty()方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

Object.defineProperty(obj, prop, descriptor)

  • obj:要定义属性的对象。
  • prop:要定义或修改的属性的名称或 Symbol 。
  • descriptor:要定义或修改的属性描述符。

返回值:被传递给函数的对象。

响应实现

对象类型

通过Object.defineProperty()对属性的读取、修改进行拦截(数据劫持)。

数组类型

通过重写更新数组的一系列方法来实现拦截(对数组的变更方法进行了包裹)。

let person = {   // 模拟Vue2实现响应式
	name:'亮哥',
	age:18   
}
 Object.defineProperty(person, "age", {
 // 当该属性的 configurable 为 true 时,该属性描述符才能够被改变,同时该属性也能从对应的对象上被删除,解决新增/删除属性,数据无响应问题
 configurable: true, 
 get: () => { 
 // 收集依赖代码...
   return person.age;
 },
 set: (newVal) => { // 一个给属性提供 setter 的方法
   // 当属性值发生变化时我们可以进行额外操作 如调用监听器
   person.age = newVal;
   // 通知更新视图代码...
 },
   });   
 data.age = 25 // 触发set方法
Copier après la connexion
  • 存在问题
    • 递归遍历数据对象属性,消耗大
    • 新增/删除属性,数据无响应;需要额外方法实现(Vue.set/Vue.delete、this.set/set/get/$delete)
    • 数组修改需要额外方法实现(Vue.set),或者通过重写的push/pop/shift/unshift/splice/sort/reverse方法实现;

Vue3.0的响应式

  • Proxy和Reflect实现响应式原理

    • 通过Proxy(代理): 拦截对象中任意属性的变化, 包括:属性值的读写、属性的添加、属性的删除等。
    • 通过Reflect(反射): 对源对象的属性进行操作。

    下面分别看看Proxy和Reflect是啥,怎么这么强能实现响应式的呢。

    卷起来,已经迫不及待想了解了解一下 ⊙.⊙

Proxy

         let data = {   // 模拟Vue2实现响应式
                name:'强哥',
                age:20   
            }
          const proxy =   new Proxy(data, {
            // 拦截读取属性值
            get (target, prop) {
                return Reflect.get(target, prop)
            },
            // 拦截设置属性值或添加新属性
            set (target, prop, value) {
                return Reflect.set(target, prop, value)
            },
            // 拦截删除属性
            deleteProperty (target, prop) {
                return Reflect.deleteProperty(target, prop)
            }
        })
        
        proxy.name = 'tom'
Copier après la connexion

上面的代码对data数组架设了一层拦截,重定义了属性的读取(get)和设置(set)行为。

作为构造函数,Proxy

Réactivité de Vue2.x🎜

🎜Vue2 implémente le piratage de données via Object.defineProperty, permettant aux données d'être mises à jour de manière réactive. La méthode Object.defineProperty() définit directement une nouvelle propriété sur un objet, ou modifie une propriété existante d'un objet, et renvoie l'objet. 🎜🎜🎜Object.defineProperty(obj, prop, descriptor)🎜🎜
  • obj : L'objet dont les propriétés doivent être définies.
  • prop : Le nom ou le symbole de la propriété à définir ou à modifier.
  • descripteur : Le descripteur d'attribut à définir ou à modifier.
🎜Valeur de retour : l'objet passé à la fonction. 🎜🎜🎜Mise en œuvre de la réponse🎜🎜

🎜Type d'objet🎜

🎜Lire et modifier les propriétés via Object.defineProperty()< code>Interception< /code> (piratage de données). 🎜

🎜Array type🎜

🎜 implémente l'interception en réécrivant une série de méthodes qui mettent à jour les tableaux (pour The la méthode de mutation du tableau est encapsulée). 🎜
const objProxy = new Proxy(obj,{
      has:function(target,key){
         return Reflect.has(target,key)
      }
      set:function(target,key,value){
         return Reflect.set(target,key,value)
      }
      get:function(target,key){
         return Reflect.get(target,key)
      }
      deleteProperty:function(target,key){
         return Reflect.deleteProperty(target,key)
      }
})
Copier après la connexion
Copier après la connexion
  • Il y a un problème
    • Traversée récursive des propriétés de l'objet de données, ce qui consomme beaucoup d'argent
    • Ajouter/supprimer propriétés, les données ne répondent pas ; implémentation de méthode supplémentaire (Vue.set/Vue.delete, this. set/set/< span class="katex-html" aria-hidden="true">set/< /span>get/$delete)
    • La modification du tableau nécessite l'implémentation d'une méthode supplémentaire (Vue.set), ou via une réécriture Implémentation de la méthode push/pop/shift/ Unshift/splice/sort/reverse

🎜Le style réactif de Vue3.0 ; 🎜

  • 🎜Proxy et Reflect implémentent le principe réactif🎜
    • Through Proxy (proxy) : intercepte les modifications de tous les attributs de l'objet, notamment : lecture et écriture des valeurs d'attributs, ajout d'attributs, suppression d'attributs, etc.
    • Par Reflect : agissez sur les propriétés de l'objet source.
    🎜Voyons ce que sont respectivement Proxy et Reflect, et comment ils peuvent être si puissants et réactifs. 🎜🎜Enroulez-le, j'ai hâte d'en savoir plus⊙.⊙🎜

🎜Proxy🎜

function reactive(target = {}) {
  if (typeof target !== "object" || target == null) {
    return target
  }

  // 代理配置
  const proxyConf = {
    get(target, key, receiver) {
      //只监听对象本身(非原型)属性
      const ownKeys = Reflect.ownKeys(target)
      if (ownKeys.includes(key)) {
        //如果是本身的属性就监听,如果是对象原型的属性就不监听
        console.log("get", key)
      }
        
      const result = Reflect.get(target, key, receiver)
      //(惰性)深度监听-->提升性能
      return reactive(result)
    },
    set(target, key, val, receiver) {
      // 重复的数据不处理
      if (val === target[key]) {
        return true
      }

      // 监听是否是新增的key
      const ownKeys = Reflect.ownKeys(target)
      if (ownKeys.includes(key)) {
        console.log("已有的key", key)
      } else {
        console.log("新增的key", key)
      }

      const result = Reflect.set(target, key, val, receiver)
      console.log("set", key, val)
      return result //通过return的值可以看出是否设置成功
    },
    deleteProperty(target, key) {
      const result = Reflect.deleteProperty(target, key)
      console.log("delete property", key)
      return result //是否删除成功
    },
  }

  // 生成代理对象
  const observed = new Proxy(target, proxyConf)
  return observed
}
Copier après la connexion
Copier après la connexion
🎜Ce qui précède le code est correct pour data met en place une couche d'interception, redéfinissant la lecture (get) et le comportement (set) des attributs. 🎜🎜En tant que constructeur, Proxy accepte deux paramètres : 🎜
  • 第一个参数是所要代理的目标对象(上例是一个data对象),即如果没有Proxy的介入,操作原来要访问的就是这个data对象。这里的对象指对象类型(数组也是对象类型)。
  • 第二个参数是一个配置对象handler,对于每一个被代理的操作,需要提供一个对应的处理函数,该函数将拦截对应的操作。比如,上面代码中,配置对象有一个get方法,用来拦截对目标对象属性的访问请求。get方法的两个参数分别是目标对象和所要访问的属性。

注意: 要使Proxy起作用,必须针对Proxy实例(上例是dataProxy对象)进行操作,而不是针对目标对象(上例是data对象)进行操作。

可以看出Proxy不仅可以实现Object.defineProperties的功能,还有其他的操作也可以拦截。

Reflect

说完Proxy就必须要说一说Reflect这个ES6新增的API。Reflect对象和Proxy对象一样也是用来操作对象的,但是Reflect对象的设计目的有重大的意义。

Reflect是一个内置的对象,它提供拦截 JavaScript 操作的方法。Reflect不是一个函数对象,因此它是不可构造的。Reflect的所有的方法都是静态的就和Math一样,目前它还没有静态属性。

Reflect的常见方法

我们可以将之前Proxy案例中对原对象的操作都修改为Reflect来操作

const objProxy = new Proxy(obj,{
      has:function(target,key){
         return Reflect.has(target,key)
      }
      set:function(target,key,value){
         return Reflect.set(target,key,value)
      }
      get:function(target,key){
         return Reflect.get(target,key)
      }
      deleteProperty:function(target,key){
         return Reflect.deleteProperty(target,key)
      }
})
Copier après la connexion
Copier après la connexion

响应式代码

function reactive(target = {}) {
  if (typeof target !== "object" || target == null) {
    return target
  }

  // 代理配置
  const proxyConf = {
    get(target, key, receiver) {
      //只监听对象本身(非原型)属性
      const ownKeys = Reflect.ownKeys(target)
      if (ownKeys.includes(key)) {
        //如果是本身的属性就监听,如果是对象原型的属性就不监听
        console.log("get", key)
      }
        
      const result = Reflect.get(target, key, receiver)
      //(惰性)深度监听-->提升性能
      return reactive(result)
    },
    set(target, key, val, receiver) {
      // 重复的数据不处理
      if (val === target[key]) {
        return true
      }

      // 监听是否是新增的key
      const ownKeys = Reflect.ownKeys(target)
      if (ownKeys.includes(key)) {
        console.log("已有的key", key)
      } else {
        console.log("新增的key", key)
      }

      const result = Reflect.set(target, key, val, receiver)
      console.log("set", key, val)
      return result //通过return的值可以看出是否设置成功
    },
    deleteProperty(target, key) {
      const result = Reflect.deleteProperty(target, key)
      console.log("delete property", key)
      return result //是否删除成功
    },
  }

  // 生成代理对象
  const observed = new Proxy(target, proxyConf)
  return observed
}
Copier après la connexion
Copier après la connexion

Vue3的响应式逻辑如何一步一步构造出来的,我放在另一篇博文Vue3响应式实现逻辑

https://juejin.im/post/6854573217038893070

【相关视频教程推荐:web前端

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:juejin.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal