网络编程
位置:首页>> 网络编程>> JavaScript>> Vue2 响应式系统之深度响应

Vue2 响应式系统之深度响应

作者:windliang  发布时间:2024-04-26 17:40:05 

标签:Vue2,响应式,系统,深度,响应

1、场景

import { observe } from "./reactive";
import Watcher from "./watcher";
const data = {
   text: {
       innerText: {
           childText: "hello",
       },
   },
};
observe(data);
const updateComponent = () => {
   console.log(data.text.innerText.childText);
};

new Watcher(updateComponent);
data.text.innerText.childText = "liang";

我们的响应式系统到现在还没有支持属性是对象时候的响应,因此我们改变 的时候不会有任何输出。childText

我们只收集了 的依赖,所以如果想要响应的话必须给 整个赋值为一个新对象。data.textdata.text

import { observe } from "./reactive";
import Watcher from "./watcher";
const data = {
   text: {
       innerText: {
           childText: "hello",
       },
   },
};
observe(data);
const updateComponent = () => {
   console.log(data.text.innerText.childText);
};

new Watcher(updateComponent);
data.text = {
   innerText: {
       childText: "liang",
   },
};

Vue2 响应式系统之深度响应

我们当然不希望每次都赋值整个对象,我们需要做一些修改,把嵌套的对象也变成响应式的。

2、方案

我们只需要在给某个 重写 和 之前,把它的 就像上边给 调用 函数一样,也调用一次 函数即可。keygetsetvaluedataobserveobserve

同时提供 参数,留下扩展,让外界决定是否需要深度响应。shallow

/*******************新增 shallow*******************/
export function defineReactive(obj, key, val, shallow) {
/****************************************************/
   const property = Object.getOwnPropertyDescriptor(obj, key);
   // 读取用户可能自己定义了的 get、set
   const getter = property && property.get;
   const setter = property && property.set;
   // val 没有传进来话进行手动赋值
   if ((!getter || setter) && arguments.length === 2) {
       val = obj[key];
   }
   const dep = new Dep(); // 持有一个 Dep 对象,用来保存所有依赖于该变量的 Watcher
   /*******************新增****************************/
   !shallow && observe(val);
 /******************************************************/
   Object.defineProperty(obj, key, {
       enumerable: true,
       configurable: true,
       get: function reactiveGetter() {
           const value = getter ? getter.call(obj) : val;
           if (Dep.target) {
               dep.depend();
           }
           return value;
       },
       set: function reactiveSetter(newVal) {
           const value = getter ? getter.call(obj) : val;

if (setter) {
               setter.call(obj, newVal);
           } else {
               val = newVal;
           }
           dep.notify();
       },
   });
}

同时,在 函数中,传进来的 不是对象的话我们直接 。observevaluereturn

/*
util.js
export function isObject(obj) {
   return obj !== null && typeof obj === "object";
}
*/
export function observe(value) {
   if (!isObject(value)) {
       return;
   }
   let ob = new Observer(value);
   return ob;
}

3、场景2

import { observe } from "./reactive";
import Watcher from "./watcher";
const data = {
   text: {
       innerText: {
           childText: "hello",
       },
   },
};
observe(data);
const updateComponent = () => {
   console.log(data.text.innerText.childText);
};

new Watcher(updateComponent);

data.text.innerText.childText = "liang";
data.text = {
   innerText: {
       childText: "liang2",
   },
};

data.text.innerText.childText = "liang3";

可以一分钟想一下上边会输出什么。

new Watcher(updateComponent); ,执行一次 输出 。updateComponenthello

data.text.innerText.childText = "liang"; ,我们已经解决了属性是对象的情况,因此这里也会输出 。liang

data.text = {
   innerText: {
       childText: "liang2",
   },
};

上边代码就是文章最开头的方法,因此也会触发函数执行,输出 。liang2

data.text.innerText.childText = "liang3"; 最后这句会执行吗?

答案是否定的了,因为我们的 赋值为了一个新对象,但这个新对象我们并没有将其设置为响应式的。data.text

因此我们需要在 的时候把对象也设置为响应式的。set

/**
* Define a reactive property on an Object.
*/
export function defineReactive(obj, key, val, shallow) {
   const property = Object.getOwnPropertyDescriptor(obj, key);
   // 读取用户可能自己定义了的 get、set
   const getter = property && property.get;
   const setter = property && property.set;
   // val 没有传进来话进行手动赋值
   if ((!getter || setter) && arguments.length === 2) {
       val = obj[key];
   }
   const dep = new Dep(); // 持有一个 Dep 对象,用来保存所有依赖于该变量的 Watcher

let childOb = !shallow && observe(val);
   Object.defineProperty(obj, key, {
       enumerable: true,
       configurable: true,
       get: function reactiveGetter() {
           const value = getter ? getter.call(obj) : val;
           if (Dep.target) {
               dep.depend();
           }
           return value;
       },
       set: function reactiveSetter(newVal) {
           const value = getter ? getter.call(obj) : val;

if (setter) {
               setter.call(obj, newVal);
           } else {
               val = newVal;
           }
         /******新增 *************************/
           childOb = !shallow && observe(newVal);
          /************************************/
           dep.notify();
       },
   });
}

4、总结

通过递归解决了属性是对象的依赖,可以为未来数组的依赖留下基础。

来源:https://vue.windliang.wang/

0
投稿

猜你喜欢

手机版 网络编程 asp之家 www.aspxhome.com