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 相关文章推荐
腾讯与新浪的通过IP地址获取当前地理位置(省份)的接口
Jul 26 Javascript
js中opener与parent的区别详细解析
Jan 14 Javascript
js匿名函数的调用示例(形式多种多样)
Aug 20 Javascript
jQuery中parentsUntil()方法用法实例
Jan 07 Javascript
BOOTSTRAP时间控件显示在模态框下面的bug修复
Feb 05 Javascript
jQuery给多个不同元素添加class样式的方法
Mar 26 Javascript
jquery表单验证需要做些什么
Nov 17 Javascript
Bootstrap编写一个兼容主流浏览器的受众巨幕式风格页面
Jul 01 Javascript
基于JavaScript实现图片连播和联级菜单实例代码
Jul 28 Javascript
JS图片懒加载的优点及实现原理
Jan 10 Javascript
flexible.js实现移动端rem适配方案
Apr 07 Javascript
Javascript原型链及instanceof原理详解
May 25 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 checkbox复选框值的获取与checkbox默认值输出方法
2010/05/15 PHP
php生成RSS订阅的方法
2015/02/13 PHP
php使用for语句输出三角形的方法
2015/06/09 PHP
thinkPHP自动验证、自动添加及表单错误问题分析
2016/10/17 PHP
laravel 实现上传图片到本地和前台访问示例
2019/10/21 PHP
DOM相关内容速查手册
2007/02/07 Javascript
JavaScript ( (__ = !$ + $)[+$] + ({} + $)[_/_] +({} + $)[_/_] )
2011/02/25 Javascript
扩展jquery实现客户端表格的分页、排序功能代码
2011/03/16 Javascript
两种不同的方法实现js对checkbox进行全选和反选
2014/05/13 Javascript
JS实现简单路由器功能的方法
2015/05/27 Javascript
jQuery 遍历函数详解
2015/07/05 Javascript
关于在Servelet中如何获取当前时间的操作方法
2016/06/28 Javascript
jQuery获取table下某一行某一列的值实现代码
2017/04/07 jQuery
Bootstrap实现基于carousel.js框架的轮播图效果
2017/05/02 Javascript
node.js调用Chrome浏览器打开链接地址的方法
2017/05/17 Javascript
webpack 2.x配置reactjs基本开发环境详解
2017/08/08 Javascript
GOJS+VUE实现流程图效果
2018/12/01 Javascript
详解关于html,css,js三者的加载顺序问题
2019/04/10 Javascript
js简单的分页器插件代码实例
2019/09/11 Javascript
jQuery 隐藏/显示效果函数用法实例分析
2020/05/20 jQuery
vue项目,代码提交至码云,iconfont的用法说明
2020/07/30 Javascript
Nodejs在局域网配置https访问的实现方法
2020/10/17 NodeJs
react+antd 递归实现树状目录操作
2020/11/02 Javascript
[00:55]2015国际邀请赛中国区预选赛5月23日——28日约战上海
2015/05/25 DOTA
[03:12]2016完美“圣”典风云人物:单车专访
2016/12/02 DOTA
Python中atexit模块的基本使用示例
2015/07/08 Python
解决pip install的时候报错timed out的问题
2018/06/12 Python
django获取from表单multiple-select的value和id的方法
2019/07/19 Python
python3.7+selenium模拟淘宝登录功能的实现
2020/05/26 Python
Python基础教程(一)——Windows搭建开发Python开发环境
2020/07/20 Python
1688平价精选商城:阿里集团旗下,工厂出厂价格直销
2017/04/24 全球购物
设计部经理的岗位职责
2013/11/16 职场文书
机械工程师的岗位职责
2013/11/17 职场文书
学生上课看漫画的检讨书
2014/09/26 职场文书
优秀教育工作者事迹材料
2014/12/24 职场文书
MySQL范围查询优化的场景实例详解
2022/06/10 MySQL