我们说到如果监听的属性是个对象呢?那么这个对象中的其他属性岂不就是监听不了了吗?如下:

  倘若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)的更多相关文章

  1. 模拟源码深入理解Vue数据驱动原理(1)

    Vue有一核心就是数据驱动(Data Driven),允许我们采用简洁的模板语法来声明式的将数据渲染进DOM,且数据与DOM是绑定在一起的,这样当我们改变Vue实例的数据时,对应的DOM元素也就会改变 ...

  2. 挖掘隐藏在源码中的Vue技巧!

    前言 最近关于Vue的技巧文章大热,我自己也写过一篇(vue开发中的"骚操作"),但这篇文章的技巧是能在Vue的文档中找到蛛丝马迹的,而有些文章说的技巧在Vue文档中根本找不到踪迹 ...

  3. jQuery 2.0.3 源码分析Sizzle引擎解析原理

    jQuery 2.0.3 源码分析Sizzle引擎 - 解析原理 声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 先来回答博友的提问: 如何解析 div > p + ...

  4. Vue源码学习1——Vue构造函数

    Vue源码学习1--Vue构造函数 这是我第一次正式阅读大型框架源码,刚开始的时候完全不知道该如何入手.Vue源码clone下来之后这么多文件夹,Vue的这么多方法和概念都在哪,完全没有头绪.现在也只 ...

  5. Vue源码分析(二) : Vue实例挂载

    Vue源码分析(二) : Vue实例挂载 author: @TiffanysBear 实例挂载主要是 $mount 方法的实现,在 src/platforms/web/entry-runtime-wi ...

  6. storm源码之理解Storm中Worker、Executor、Task关系 + 并发度详解

    本文导读: 1 Worker.Executor.task详解 2 配置拓扑的并发度 3 拓扑示例 4 动态配置拓扑并发度 Worker.Executor.Task详解: Storm在集群上运行一个To ...

  7. 老李推荐:第14章9节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-遍历控件树查找控件

    老李推荐:第14章9节<MonkeyRunner源码剖析> HierarchyViewer实现原理-遍历控件树查找控件   poptest是国内唯一一家培养测试开发工程师的培训机构,以学员 ...

  8. 老李推荐:第14章5节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-装备ViewServer-查询ViewServer运行状态

    老李推荐:第14章5节<MonkeyRunner源码剖析> HierarchyViewer实现原理-装备ViewServer-查询ViewServer运行状态   poptest是国内唯一 ...

  9. 老李推荐:第14章6节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-装备ViewServer-启动ViewServer

    老李推荐:第14章6节<MonkeyRunner源码剖析> HierarchyViewer实现原理-装备ViewServer-启动ViewServer   poptest是国内唯一一家培养 ...

随机推荐

  1. DEADBEEF

    “DEADBEEF”是什么?可能很多人都没有听说过.DEADBEEF不是“死牛肉”的意思,而是一个十六进制数字,即0xDEADBEEF.最初使用它的是IBM的RS/6000系统.在该系统中,已分配但还 ...

  2. spring cloud报错解决:java.lang.ClassNotFoundException: com.netflix.servo.monitor.Monitors

    见鬼的事发生了. 在家里电脑上拿样例代码,运行时OK的.但一到公司电脑,用同样的代码,就会报下面的错误 ===================== Caused by: java.lang.Class ...

  3. Linux下安装rz、sz命令(文件上传下载)

    yum install -y lrzsz 说明:rz命令本地上传文件到服务器:sz命令发送文件到本地.

  4. Notepad++7.4.2的配置使用详情

    之前有写过一篇notepad的使用说明,没想到稀里糊涂更新了几次之后,我以前的配置什么的全干掉了,而且我打开新版后,发现和以前还有点不一样了.那就继续这个高级版本再来一边吧. 1.Zen Coding ...

  5. webStorm配置es6转es5

    话说又开始新项目了,刚好今天学习的es6新语法可以试试手,回到家后开始继续学习,然后只是学习es6没有必要弄个gulp,总觉得浪费. 那么前端开发神器的webStorm是一定会支持es6的,于是百度了 ...

  6. Win7 + VirtualBox + CentOS (服务器版 无桌面) 使用共享文件夹

    http://jingyan.baidu.com/article/b2c186c8ffb607c46ff6ff61.html

  7. 524. Longest Word in Dictionary through Deleting【Medium】【删除后得到的字典中的最长单词】

    Given a string and a string dictionary, find the longest string in the dictionary that can be formed ...

  8. java Integer parseInt()

    先来一段代码,代码很简单的,如下: public static void main(String[] args) { Integer a = Integer.parseInt("3" ...

  9. Python开发基础-Day20继承实现原理、子类调用父类的方法、封装

    继承实现原理 python中的类可以同时继承多个父类,继承的顺序有两种:深度优先和广度优先. 一般来讲,经典类在多继承的情况下会按照深度优先的方式查找,新式类会按照广度优先的方式查找 示例解析: 没有 ...

  10. BZOJ 1106 [POI2007]立方体大作战tet(树状数组)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1106 [题目大意] 给定玩家一个有2n个元素的栈,元素一个叠一个地放置. 这些元素拥有 ...