一、前言

在随笔“模拟Vue之数据驱动1”结尾处,我们说到如果监听的属性是个对象呢?那么这个对象中的其他属性岂不就是监听不了了吗?

如下:

倘若user中的name、age属性变化,如何知道它们变化了呢?

今儿,就来解决这一问题。

通过走读Vue源码,发现他是利用Observer构造函数为每个对象创建一个Observer对象,来监听数据的,如果数据中的属性又是一个对象,那么就又通过Observer来监听嘛。

其实,核心思想就是树的先序遍历(关于树,可参考here)。如我们将上述Demo中的data数据,图形化一下,就更加明白了,如下:

好了,理清了大体思路,下面我们就一起来创建一个Observer吧。

二、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以及convert方法吧。

-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;
}
}
});
}

好了,到此,一个简单的Observer就构造完成,下面我们就来测试下,是否成功监听了每个属性。

<script src="./observer.js"></script>
<script>
let data = {
user: {
name: 'Monkey',
age: 24
},
lover: {
name: 'Dorie',
age: 23
}
};
Observer(data);
</script>

效果如下:

Perfect,完整代码见github 

模拟Vue之数据驱动2的更多相关文章

  1. 模拟Vue之数据驱动3

    一.前言 在"模拟Vue之数据驱动2"中,我们实现了个Observer构造函数,通过它可以达到监听已有数据data中的所有属性. 但,倘若我们想在某个对象中,新增某个属性呢? 如下 ...

  2. 模拟Vue之数据驱动4

    一.前言 在"模拟Vue之数据驱动3"中,我们实现了为每个对象扩展一个$set方法,用于新增属性使用,这样就可以监听新增的属性了. 当然,数组也是对象,也可以通过$set方法实现新 ...

  3. 模拟Vue之数据驱动5

    一.前言 在"模拟Vue之数据驱动4"中,我们实现了push.pop等数组变异方法. 但是,在随笔末尾我们提到,当pop.sort这些方法触发后,该怎么办呢?因为其实,它们并没有往 ...

  4. 模拟Vue之数据驱动

    一.前言 在随笔"模拟Vue之数据驱动1"结尾处,我们说到如果监听的属性是个对象呢?那么这个对象中的其他属性岂不就是监听不了了吗? 如下: 倘若user中的name.age属性变化 ...

  5. 模拟Vue之数据驱动1

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

  6. 模拟vue的tag属性,在react里实现自定义Link

    我封装了一个简单的实现react里自定义Link的方法,方便大家使用. 因为普通组件没有metch.location.history等属性.只有在<Router>里面的<compon ...

  7. vue-toy: 200行代码模拟Vue实现

    vue-toy 200行左右代码模拟vue实现,视图渲染部分使用React来代替Snabbdom,欢迎Star. 项目地址:https://github.com/bplok20010/vue-toy ...

  8. vue实现数据驱动视图原理

    一.什么是数据驱动 数据驱动是vuejs最大的特点.在vuejs中,所谓的数据驱动就是当数据发生变化的时候,用户界面发生相应的变化,开发者不需要手动的去修改dom. 比如说我们点击一个button,需 ...

  9. 模拟vue实现简单的webpack打包

    一.安装nodejs,查看是否安装成功 二.package.json项目初始化 npm init 电脑有node环境,在根目录下运行命令npm init初始化项目,根据提示输入项目相关信息,然后运行. ...

随机推荐

  1. WCF的回调使用实例代码说明

    很多时候我们会遇到,信息及时推送通知的情况,例如:监控设备时及时推送状态.报警信息等,我们就可以用WCF的回调机制来实现,下面以一个监控设备名字为例,如果设备名字发生改变,服务器就马上推送消息给客户端 ...

  2. Android 百度地图 SDK v3.0.0 (三) 添加覆盖物Marker与InfoWindow的使用

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/37737213 上篇博客已经实现了地图的定位以及结合了方向传感器用户路痴定位方向, ...

  3. C++标准库<string>简单总结

    C++标准库<string>简单总结 在C++中,如果需要对字符串进行处理,那么它自带的标准库<string>无疑是最好的选择,它实现了很多常用的字符处理函数. 要想使用标准C ...

  4. tomcat加载不了spring-webjar终极解决办法

    Problems: I included: all Spring libs, Apache Tomcat 7.0 library in Build Path but it still gives er ...

  5. memcache缓存命中深入理解转载

    http://www.iteye.com/topic/225692 memcache的方法有 add,set,replace,get,delete,getstats,increment,decreme ...

  6. android studio 改变主题及字体大小

    一丶修改主题背景 1.点击图中的小扳子图标(设置),或者点击file->setting-> 2.找到Appearance->在Theme中选择Darcula,即可改变成当前最主流的主 ...

  7. java.sql.SQLException: ORA-00604: 递归 SQL 级别 1 出现错误

    后台报出如下错误: Caused by: java.sql.SQLException: ORA-00604: 递归 SQL 级别 1 出现错误 ORA-01000: 超出打开游标的最大数 ORA-00 ...

  8. 用css3实现闪烁效果

    1. css3 @keyframes 参考 css3 @keyframes规则. 特别注意浏览器支持: Internet Explorer 10, Firefox, 和 Opera 支持 @keyfr ...

  9. java事件处理

    1.ActionEven事件 文本框,按钮,菜单项,密码框,单选按钮都可以出发ActionEvent事件 使用 addActionListener(ActionListener listen1) 来注 ...

  10. hdu1233(最小生成树)

    Problem Description 某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离.省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能 ...