Vue数据驱动模拟实现2


Posted in Javascript onJanuary 11, 2017

一、前言

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

如下:

 Vue数据驱动模拟实现2

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

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

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

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

Vue数据驱动模拟实现2 

好了,理清了大体思路,下面我们就一起来创建一个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>

效果如下:

Vue数据驱动模拟实现2

Perfect,完整代码见github。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
网页前台通过js非法字符过滤代码(骂人的话等等)
May 26 Javascript
javascript模拟实现ajax加载框实例
Oct 15 Javascript
运用jQuery定时器的原理实现banner图片切换
Oct 22 Javascript
JS中Location使用详解
May 12 Javascript
js实现全国省份城市级联下拉菜单效果代码
Sep 07 Javascript
jQuery实现横向带缓冲的水平运动效果(附demo源码下载)
Jan 29 Javascript
JS修改地址栏参数实例代码
Jun 14 Javascript
JS获取鼠标选中的文字
Aug 10 Javascript
javascript如何创建对象
Aug 29 Javascript
vue 2.0 购物车小球抛物线的示例代码
Feb 01 Javascript
使用axios发送post请求,将JSON数据改为form类型的示例
Oct 31 Javascript
JS自定义右键菜单实现代码解析
Jul 16 Javascript
jQuery实现对象转为url参数的方法
Jan 11 #Javascript
将鼠标焦点定位到文本框最后(代码分享)
Jan 11 #Javascript
移动端界面的适配
Jan 11 #Javascript
bootstrapValidator bootstrap-select验证不可用的解决办法
Jan 11 #Javascript
HTML5 js实现拖拉上传文件功能
Nov 20 #Javascript
Bootstrap表单控件使用方法详解
Jan 11 #Javascript
老生常谈的跨域处理
Jan 11 #Javascript
You might like
WordPress判断用户是否登录的代码
2011/03/17 PHP
simplehtmldom Doc api帮助文档
2012/03/26 PHP
php的mssql数据库连接类实例
2014/11/28 PHP
在云虚拟主机部署thinkphp5项目的步骤详解
2017/12/21 PHP
PHP实现的AES 128位加密算法示例
2019/09/16 PHP
在网页中使用document.write时遭遇的奇怪问题
2010/08/24 Javascript
解析prototype,JQuery中跳出each循环的方法
2013/12/12 Javascript
基于jquery实现一个滚动的分步注册向导-附源码
2015/08/26 Javascript
jQuery+Ajax实现无刷新分页
2015/10/30 Javascript
JavaScript Date对象详解
2016/03/01 Javascript
jQuery替换节点元素的操作方法
2018/03/18 jQuery
解决IE11 vue +webpack 项目中数据更新后页面没有刷新的问题
2018/09/25 Javascript
JS判断数组四种实现方法详解
2020/06/29 Javascript
微信小程序实现自定义动画弹框/提示框的方法实例
2020/11/06 Javascript
Python FTP操作类代码分享
2014/05/13 Python
Python数据结构与算法之图的最短路径(Dijkstra算法)完整实例
2017/12/12 Python
解决python3 安装完Pycurl在import pycurl时报错的问题
2018/10/15 Python
Python小工具之消耗系统指定大小内存的方法
2018/12/03 Python
python实现多层感知器MLP(基于双月数据集)
2019/01/18 Python
Django框架用户注销功能实现方法分析
2019/05/28 Python
PyQt5实现让QScrollArea支持鼠标拖动的操作方法
2019/06/19 Python
Django CBV与FBV原理及实例详解
2019/08/12 Python
Python图像处理库PIL中图像格式转换的实现
2020/02/26 Python
解决keras backend 越跑越慢问题
2020/06/18 Python
如何基于python把文字图片写入word文档
2020/07/31 Python
手机端用rem+scss做适配的详解
2017/11/15 HTML / CSS
Perry Ellis官网:美国男士品味服装
2016/12/09 全球购物
美国顶级防滑鞋:Shoes For Crews
2017/03/27 全球购物
泰国第一的化妆品网站:Konvy
2018/02/25 全球购物
英国剑桥包中文官网:The Cambridge Satchel Company中国
2018/11/06 全球购物
Ticketmaster意大利:音乐会、节日、艺术和剧院的官方门票
2019/12/23 全球购物
20年同学聚会感言
2014/02/03 职场文书
2015年幼儿园元旦亲子活动方案
2014/12/09 职场文书
2016春季幼儿园开学寄语
2015/12/03 职场文书
深度学习小工程练习之垃圾分类详解
2021/04/14 Python
vue @click.native 绑定原生点击事件
2022/04/22 Vue.js