模拟源码深入理解Vue数据驱动原理(2)
我们说到如果监听的属性是个对象呢?那么这个对象中的其他属性岂不就是监听不了了吗?如下:

倘若user中的name、age属性变化,如何知道它们变化了呢?今儿,就来解决这一问题。
通过走读Vue源码,发现他是利用Observer构造函数为每个对象创建一个Observer对象,来监听数据的,如果数据中的属性又是一个对象,那么就又通过Observer来监听嘛。
其实,核心思想就是树的先序遍历。如我们将上述Demo中的data数据,图形化一下,就更加明白了,如图:
理清了大体思路,下面我们就一起来创建一个Observer。
Observer整体结构如下:
function Observer(data) {
//如若this不是Observer对象,即创建一个
if (!(this instanceof Observer)) {
return new Observer(data);
}
this.data = data;
this.walk(data);
}
let p = Observer.prototype = Object.create(null);
p.walk = function(data) {
/*
TODO:监听data数据中的所有属性,
并查看data中属性值是否为对象,
若为对象,就创建一个Observer实例
*/
}
p.convert = function(key, val) {
//TODO:通过Object.defineProperty监听数据
}
walk
首先,我们在walk方法中实现对data对象中的所有属性监听,如下:
p.walk = function(data) {
let keys = Object.keys(data);
keys.forEach(key => {
let val = data[key];
this.convert(key, val);
});
}
由于属性中可能又会是一个对象,那么,我们就有必要监听它们。怎么办呢?如果是个对象,再次利用Observer构造函数,处理它不就完了么。如下:
p.walk = function(data) {
let keys = Object.keys(data);
keys.forEach(key => {
let val = data[key];
//如果val为对象,则交给Observer处理
if (typeof val === 'object') {
Observer(val);
}
this.convert(key, val);
});
}
你可能会有这样的疑问,如果直接利用Observer处理对象,那么不就与父对象失去关联了么?
然而并没有,因为JavaScript对于对象是指向地址关系,所以怎么会失去关联呢。
convert
对于convert方法,就比较简单了,一如既往就是利用Object.defineProperty监听数据,如下:
p.convert = function(key, val) {
Object.defineProperty(this.data, key, {
get: () => {
console.log('访问了' + key + ' 值为' + val);
return val;
},
set: (newVal) => {
console.log('设置了' + key + ' 值为' + newVal);
if (newVal !== val) {
val = newVal;
}
}
});
}
完整代码:
function Observer(data) {
//如若this不是Observer对象,即创建一个
if (!(this instanceof Observer)) {
return new Observer(data);
}
this.data = data;
this.walk(data);
}
let p = Observer.prototype = Object.create(null);
p.walk = function(data) {
let keys = Object.keys(data);
keys.forEach(key => {
let val = data[key];
//如果val为对象,则交给Observer处理
if (typeof val === 'object') {
Observer(val);
}
this.convert(key, val);
});
}
p.convert = function(key, val) {
Object.defineProperty(this.data, key, {
get: () => {
console.log('访问了' + key + ' 值为' + val);
return val;
},
set: (newVal) => {
console.log('设置了' + key + ' 值为' + newVal);
if (newVal !== val) {
val = newVal;
}
}
});
}
使用:
<script>
let data = {
user: {
name: 'Monkey',
age:
},
lover: {
name: 'Dorie',
age:
}
};
Observer(data);
</script>
模拟源码深入理解Vue数据驱动原理(2)的更多相关文章
- 模拟源码深入理解Vue数据驱动原理(1)
Vue有一核心就是数据驱动(Data Driven),允许我们采用简洁的模板语法来声明式的将数据渲染进DOM,且数据与DOM是绑定在一起的,这样当我们改变Vue实例的数据时,对应的DOM元素也就会改变 ...
- 挖掘隐藏在源码中的Vue技巧!
前言 最近关于Vue的技巧文章大热,我自己也写过一篇(vue开发中的"骚操作"),但这篇文章的技巧是能在Vue的文档中找到蛛丝马迹的,而有些文章说的技巧在Vue文档中根本找不到踪迹 ...
- jQuery 2.0.3 源码分析Sizzle引擎解析原理
jQuery 2.0.3 源码分析Sizzle引擎 - 解析原理 声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 先来回答博友的提问: 如何解析 div > p + ...
- Vue源码学习1——Vue构造函数
Vue源码学习1--Vue构造函数 这是我第一次正式阅读大型框架源码,刚开始的时候完全不知道该如何入手.Vue源码clone下来之后这么多文件夹,Vue的这么多方法和概念都在哪,完全没有头绪.现在也只 ...
- Vue源码分析(二) : Vue实例挂载
Vue源码分析(二) : Vue实例挂载 author: @TiffanysBear 实例挂载主要是 $mount 方法的实现,在 src/platforms/web/entry-runtime-wi ...
- storm源码之理解Storm中Worker、Executor、Task关系 + 并发度详解
本文导读: 1 Worker.Executor.task详解 2 配置拓扑的并发度 3 拓扑示例 4 动态配置拓扑并发度 Worker.Executor.Task详解: Storm在集群上运行一个To ...
- 老李推荐:第14章9节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-遍历控件树查找控件
老李推荐:第14章9节<MonkeyRunner源码剖析> HierarchyViewer实现原理-遍历控件树查找控件 poptest是国内唯一一家培养测试开发工程师的培训机构,以学员 ...
- 老李推荐:第14章5节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-装备ViewServer-查询ViewServer运行状态
老李推荐:第14章5节<MonkeyRunner源码剖析> HierarchyViewer实现原理-装备ViewServer-查询ViewServer运行状态 poptest是国内唯一 ...
- 老李推荐:第14章6节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-装备ViewServer-启动ViewServer
老李推荐:第14章6节<MonkeyRunner源码剖析> HierarchyViewer实现原理-装备ViewServer-启动ViewServer poptest是国内唯一一家培养 ...
随机推荐
- Unique Binary Search Trees I&&II(II思路很棒)——动态规划(II没理解)
Given n, how many structurally unique BST's (binary search trees) that store values 1...n? For exa ...
- 02 java 基础:java 文件名与类名关系 CLASSPATH
java 类修饰符:通常情况下使用 public 修饰,此时,java 强制要求 .java 文件名需与该 public 修饰类名一致,否则无法编译通过.如若没有加修饰符,文件名与类名可无任何关联. ...
- HDMI 电视 点对点 桌面超出屏幕
一直在用电视作显示器,但是没有注意点对点到问题,只是感觉字体发虚.直到今天装win10,桌面会超出屏幕,使用intel控制面板调整分辨率后正常,但是注销或重启会再次回复.百度无果,自己摸索,不仅解决了 ...
- DaemonSet
What is a DaemonSet? DaemonSet能够让所有(或者一些特定)的Node节点运行同一个pod.当节点加入到kubernetes集群中,pod会被(DaemonSet)调度到该节 ...
- 转:Google Project Zero挖洞经验整理
https://www.sec-un.org/google-project-zero%E6%8C%96%E6%B4%9E%E7%BB%8F%E9%AA%8C%E6%95%B4%E7%90%86/ 1. ...
- 洛谷P3197 HNOI2008 越狱
题目传送门 实际上昨天大鸡哥已经讲过这题了,结果没记住,今天一道相似的题就挂了......吃一堑长一智啊. 思路大致是这样:如果直接算发生越狱的情况会比较复杂,所以可以用间接法,用安排的总方案-不会发 ...
- 丑数(LintCode)
丑数 设计一个算法,找出只含素因子3,5,7 的第 k大的数. 符合条件的数如:3,5,7,9,15...... 您在真实的面试中是否遇到过这个题? Yes 样例 如果k=4, 返回 9 挑战 要求时 ...
- [BZOJ3529]数表
假设$n\leq m$,我们先不考虑$\leq a$的限制 $\sum\limits_{i=1}^n\sum\limits_{j=1}^m\sigma((i,j))=\sum\limits_{T=1} ...
- 【动态规划】【二分】CDOJ1006 最长上升子序列
最长上升子序列. 要求输出字典序最小解. 就在更新答案的时候记录一下前驱.容易发现记录的这个玩意实际上形成了一个森林. #include<cstdio> #include<algor ...
- 判断隐式Intent是否有响应
PackageManager manager = getContext().getPackageManager(); if (manager.queryIntentActivities(intent, ...