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.text
data.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、方案
我们只需要在给某个 重写 和 之前,把它的 就像上边给 调用 函数一样,也调用一次 函数即可。key
get
set
value
data
observe
observe
同时提供 参数,留下扩展,让外界决定是否需要深度响应。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();
},
});
}
同时,在 函数中,传进来的 不是对象的话我们直接 。observe
value
return
/*
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);
,执行一次 输出 。updateComponent
hello
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
投稿
猜你喜欢
- 当然还是要使用FileSystemObject(FSO)来创建了。不过在创建前,要先检查以下目录是否存在,如果存在,就不用创建了: 
- 生成Fiboncci Fn数有Θ(1),Θ(n)甚至指数级的算法,不过有Θ(log n)的吗?告诉你,有。首先,关于Fibonacci数,有
- 1.在查询结果中显示列名: a.用as关键字:select name as '姓名' from students order
- 作为一个网页设计师,不知道各位是否有这样的经历:客户给你的网站材料很多都是Word文档,虽然阅读起来很
- 我们知道numpy.ndarray.reshape()是用来改变numpy数组的形状的,但是它的参数会有一些特殊的用法,这里我们进一步说明一
- 一.使用DOM生成和读取XML文件 实例一: <?php //Creates XML string and XML document
- 浏览器:IE ,不支持firefoxfilter视觉滤镜的种类:Alpha(透明度) Blur(模糊) Chroma(指定颜色透明) Dro
- 画星星程序2-7-7主要使用turtle.forward前进操作和turtle.left左转操作在屏幕上画星星。#!/usr/bin/env
- Python开发环境配置好了,但发现自带的代码编辑器貌似用着有点不大习惯啊,所以咱们就找一个“好用的”代码编辑器吧,网上搜了一下资料,Pyt
- 如下所示:#!/usr/bin/env python3# -*- coding: utf-8 -*-import sqlite3conn =
- 今天来给大家推荐一个Python当中超级好用的内置函数,那便是lambda方法,本篇教程大致和大家分享什么是lambda函数lambda函数
- 摘要:Ffrpc可以很方便的构建c++ server, 在网游服务器程序开发中,进程间通讯非常的重要,比如gateserver和gamese
- 假设有一个可迭代对象,现在想要对它内部的元素进行排序,我们一般会使用内置函数 sorted,举个例子:data = (3
- 字符串遍历>>> a_str = "hello itcast">>> for cha
- 卸载MySQL1、在控制面板,卸载MySQL的所有组件控制面板——》所有控制面板项——》程序和功能,卸载所有和MySQL有关的程序2、找到你
- 简单的‘Hello World!'Python命令行假设你已经安装好了Python, 那么在Linux命令行输入:$python将直
- mean_squared_error / mse 均方误差,常用的目标函数,公式为((y_pred-y_true)**2).mean()mo
- 作为k8s官方维护的客户端,k8s go-client对于go语言中使用k8s可以说是唯一选项。但是官方的使用示例我个人觉得并不是很清晰,尤
- The prompt command reconfigures the default mysql> prompt. The stri
- 核心播放模块(pygame内核)import time import pygameimport easygui as guifile = r