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 相关文章推荐
解析arp病毒背后利用的Javascript技术附解密方法
Aug 06 Javascript
ASP.NET jQuery 实例4(复制TextBox的文本到本地剪贴板上)
Jan 13 Javascript
基于jQuery的倒计时实现代码
May 30 Javascript
js 验证密码强弱的小例子
Mar 21 Javascript
javascript的渐进增强与平稳退化浅谈
Nov 12 Javascript
JS获取月的最后一天与JS得到一个月份最大天数的实例代码
Dec 16 Javascript
jquery ajax跨域解决方法(json方式)
Feb 04 Javascript
jQuery提交多个表单的小技巧
Jul 27 Javascript
简述AngularJS相关的一些编程思想
Jun 23 Javascript
vue页面加载闪烁问题的解决方法
Mar 28 Javascript
vue draggable resizable 实现可拖拽缩放的组件功能
Jul 15 Javascript
Vue优化:常见会导致内存泄漏问题及优化详解
Aug 04 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
php中支持多种编码的中文字符串截取函数!
2007/03/20 PHP
php Undefined index和Undefined variable的解决方法
2008/03/27 PHP
ExtJS与PHP、MySQL实现存储的方法
2010/04/02 PHP
ThinkPHP模板比较标签用法详解
2014/06/30 PHP
PHP获取毫秒级时间戳的方法
2015/04/15 PHP
php实现短信发送代码
2015/07/05 PHP
基于JQuery的Pager分页器实现代码
2010/07/17 Javascript
javascript实现图片切换的幻灯片效果源代码
2012/12/12 Javascript
JavaScript 实现简单的倒计时弹窗DEMO附图
2014/03/05 Javascript
jquery、js调用iframe父窗口与子窗口元素的方法整理
2014/07/31 Javascript
深入理解JavaScript系列(40):设计模式之组合模式详解
2015/03/04 Javascript
jQuery实现返回顶部功能
2016/02/23 Javascript
TypeScript Type Innference(类型判断)
2016/03/10 Javascript
NodeJS创建基础应用并应用模板引擎
2016/04/12 NodeJs
js的form表单提交url传参数(包含+等特殊字符)的两种解决方法
2016/05/25 Javascript
微信小程序 Nginx环境配置详细介绍
2017/02/14 Javascript
js获取指定时间的前几秒
2017/04/05 Javascript
vue2过滤器模糊查询方法
2018/09/16 Javascript
vue实现todolist基本功能以及数据存储功能实例详解
2019/04/11 Javascript
JavaScript设计模式--桥梁模式引入操作实例分析
2020/05/23 Javascript
[52:29]DOTA2上海特级锦标赛主赛事日 - 2 胜者组第一轮#3Secret VS OG第三局
2016/03/03 DOTA
[01:14]DOTA2 7.22版本新增神杖效果展示(智力英雄篇)
2019/05/29 DOTA
python实现读Excel写入.txt的方法
2018/04/29 Python
mac下pycharm设置python版本的图文教程
2018/06/13 Python
HTML5中5个简单实用的API(第二篇,含全屏、可见性、拍照、预加载、电池状态)
2014/05/07 HTML / CSS
MAC Cosmetics官方网站:魅可专业艺术彩妆
2019/04/10 全球购物
金额转换,阿拉伯数字的金额转换成中国传统的形式如:(¥1011)-> (一千零一拾一元整)输出
2015/05/29 面试题
超市后勤自我鉴定
2014/01/17 职场文书
师生聚会感言
2014/01/26 职场文书
施工材料员岗位职责
2014/02/12 职场文书
个人工作表现评语
2014/04/30 职场文书
2014年人力资源部工作总结
2014/11/19 职场文书
班主任工作实习计划
2015/01/16 职场文书
2016年教师节特级教师获奖感言
2015/12/09 职场文书
golang日志包logger的用法详解
2021/05/05 Golang
linux下安装redis图文详细步骤
2021/12/04 Redis