Vue2 响应式系统之深度响应

目录
  • 1、场景
  • 2、方案
  • 3、场景2
  • 4、总结

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",
    },
};

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

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、总结

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

到此这篇关于Vue2 响应式系统之深度响应的文章就介绍到这了,更多相关Vue2 深度响应内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Vue2 响应式系统之分支切换

    目录 场景 observer(data) new Watcher(updateComponent) data.ok = false data.text = "hello, liang" 问题 去重 重置 测试 总结 场景 我们考虑一下下边的代码会输出什么. import { observe } from "./reactive"; import Watcher from "./watcher"; const data = { text: &quo

  • Vue2响应式系统介绍

    目录 一.响应式系统要干什么 二.响应式数据 三.保存当前正在执行的函数 四.响应式数据 五.Observer 对象 六.测试 七.总结 前言: 目前工作中大概有 的需求是在用 的技术栈,所谓知其然更要知其所以然,为了更好的使用 .更快的排查问题,最近学习了源码相关的一些知识,虽然网上总结 的很多很多了,不少自己一个,但也不多自己一个,欢迎一起讨论学习,发现问题欢迎指出.40%Vue2VueVue 一.响应式系统要干什么 回到最简单的代码: data = { text: 'hello, worl

  • Vue2响应式系统之嵌套

    目录 1.场景 2.执行过程 3.修复 4.测试 5.总结 1.场景 在 开发中肯定存在组件嵌套组件的情况,类似于下边的样子.Vue <!-- parent-component --> <div> <my-component :text="inner"></my-component> {{ text }} <div> <!-- my-component--> <div>{{ text }}</di

  • Vue2 响应式系统之异步队列

    目录 场景 解决方案 代码实现 执行结果 总结 试想一下如果这里的 console.log 是渲染页面,那改变一次值就刷新一下页面,会造成严重的性能问题,页面也会不停的改变. 场景 import { observe } from "./reactive"; import Watcher from "./watcher"; const data = { a: 1, b: 2, c: 3, }; observe(data); const updateComponent

  • Vue2 响应式系统之深度响应

    目录 1.场景 2.方案 3.场景2 4.总结 1.场景 import { observe } from "./reactive"; import Watcher from "./watcher"; const data = { text: { innerText: { childText: "hello", }, }, }; observe(data); const updateComponent = () => { console.lo

  • Vue2 响应式系统之数组

    目录 1.场景 2.场景 2 3.方案 3.收集依赖代码实现 4.通知依赖代码实现 5.测试 6.总结 本文接Vue2响应式系统.Vue2 响应式系统之分支切换 ,响应式系统之嵌套.响应式系统之深度响应还没有看过的小伙伴需要看一下. 1.场景 import { observe } from "./reactive"; import Watcher from "./watcher"; const data = { list: ["hello"],

  • 浅谈Java响应式系统

    初识响应式系统 ReactiveX的本质就是Observer+Iterator+函数编程+异步.是一个事件驱动的,异步的,可观察的序列. 使用RxJava可以将异步的回调改写成为链式调用.在代码上看起来非常简洁明了.当然JDK也提供了CompletionStage提供了类似的解决回调的功能. Rxjava只是一个java的基本库,如果我们想要构建响应式的服务器,响应式的web,响应式的数据访问,甚至是响应式的微服务,又该如何处理呢? 这个时候我了解到了Vert.x.Vert.x就是用来构建Rea

  • Vue2响应式系统之set和delete

    目录 1.数组集 2.数组 del 3.对象 set 4.对象 del 5.总结 1.数组集 import { observe } from "./reactive"; import Watcher from "./watcher"; const data = { list: [1, 2], }; observe(data); const updateComponent = () => { console.log(data.list); }; new Watc

  • vue响应式系统之observe、watcher、dep的源码解析

    Vue的响应式系统 Vue 最独特的特性之一,是其非侵入性的响应式系统.数据模型仅仅是普通的JavaScript 对象,而当你修改它们时,视图会进行更新,这使得状态管理非常简单直接,我们可以只关注数据本身,而不用手动处理数据到视图的渲染,避免了繁琐的 DOM 操作,提高了开发效率. vue 的响应式系统依赖于三个重要的类:Dep 类.Watcher 类.Observer 类,然后使用发布订阅模式的思想将他们揉合在一起(不了解发布订阅模式的可以看我之前的文章发布订阅模式与观察者模式). Obser

  • Vue响应式系统的原理详解

    目录 vue响应式系统的基本原理 1.回顾一下Object.defineProperty的用法 2.实战1:使用 Object.defineProperty 对 person的age属性 进行监听 3.数据代理 4.vue中实现响应式思路 总结 1.Vue中的数据代理: 2.Vue中数据代理的好处: 3.基本原理: 4.vue中实现响应式思路 vue响应式系统的基本原理 我们使用vue时,对数据进行操作,就能影响对应的视图.那么这种机制是怎么实现的呢? 思考一下,是不是就好像我们对数据的操作 被

  • 这应该是最详细的响应式系统讲解了

    前言 本文从一个简单的双向绑定开始,逐步升级到由defineProperty和Proxy分别实现的响应式系统,注重入手思路,抓住关键细节,希望能对你有所帮助. 一.极简双向绑定 首先从最简单的双向绑定入手: // html <input type="text" id="input"> <span id="span"></span> // js let input = document.getElementByI

随机推荐