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

  倘若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. Divide Two Integers——二分法的经典变形

    Divide two integers without using multiplication, division and mod operator. If it is overflow, retu ...

  2. 【转载】关于Python的Mixin模式

    本博按: mixin是看起来是多继承的一种,但是,这种继承并不作为父类存在,而是增加功能到子类中. 像C或C++这类语言都支持多重继承,一个子类可以有多个父类,这样的设计常被人诟病.因为继承应该是个” ...

  3. C#读取RSS源,并利用Solr索引

    折磨我几天的问题今天终于解决了,分享一下近期solr使用的一些经验. 本来是用nutch在爬取页面,可是客户需要爬取RSS,而且可以识别那些页面是通过RSS源抓取出来的.nutch虽然自带解析RSS的 ...

  4. H264 帧边界识别简介

    http://blog.csdn.net/wzw88486969/article/details/50364017

  5. oracle 自己改了 spfile 导致起不来

    oracle pfile 出错 今天在升级 oracle 内存的时候参数调错了,导致 oracle 起不来, 情急之下用 vim 修改了 spfile 文件,结果由于该文件是二进制的,不能直接修改,所 ...

  6. 转型(java)(.net)

    /** * 父类 */ class Animal { public void eat() { //输出 父类吃.... } } class Bird extends Animal { public v ...

  7. Oracle基础了解

    数据库: 关系型数据库 select * from 表名 非关系型数据库(做不到复杂查询) 以对象的形式进行存储 {"aaa":"ccc"}---键值对 ora ...

  8. 洛谷——P1692 部落卫队

    题目描述 原始部落byteland中的居民们为了争夺有限的资源,经常发生冲突.几乎每个居民都有他的仇敌.部落酋长为了组织一支保卫部落的队伍,希望从部落的居民中选出最多的居民入伍,并保证队伍中任何2 个 ...

  9. Web应用主动侦测工具Skipfish

    Web应用主动侦测工具Skipfish   Skipfish是Kali Linux附带的一个主动Web应用侦测工具.该工具会首先尽可能获取所有网站路径,进行访问,然后根据返回的内容,检测是否存在漏洞. ...

  10. 利用FusionCharts制作统计报表

    今天在开发中需要用到统计报表,于是就查找了一下FusionCharts的用法,下面来总结一下利用FusionCharts怎么制作统计报表 1.建表 首先要建立所要统计报表的表,表的字段越多,统计的维度 ...