Vue数据驱动模拟实现3


Posted in Javascript onJanuary 11, 2017

一、前言

在"模拟Vue之数据驱动2"中,我们实现了个Observer构造函数,通过它可以达到监听已有数据data中的所有属性。

但,倘若我们想在某个对象中,新增某个属性呢?

如下:

Vue数据驱动模拟实现3

那么岂不是,新增的infor属性,以及它的对象属性,没有得到监听。

此时,应该怎么处理呢?

通过走读Vue源码,发现他是采用另增属性方法$set实现的。

就是说,如果我们采用常规方法为对象增加属性(如上),我们没法得知并监控它,所以,我们为每个对象扩展一个$set方法,用于另增属性使用,即可,如下:

data.user.$set('infor', {msg: 'happy'});

好了,下面,我们就一同实现这个$set方法吧。

二、$set方法实现

首先,我们得创建一个恒定extendObj对象,用于将$set方法绑定在其中。

你可能会想,为什么我们需要一个extendObj对象呢?直接将$set函数赋值给每个需要监听的对象不就完了么?

是的,这样也可以,但是随着需求增长,倘若我们又想为每个监听对象扩展其他方法呢?难道又要去Observer里面为对象,一一赋值?

so,创建恒定extendObj对象,如下:

const extendObj = {};

因为,我们将$set绑定到extendObj中,且让$set为不可枚举型,所以会用到Object.defineProperty,固将其提取出来,作为一个方法如下:

function proxyObject(obj, key, val, enume){
  Object.defineProperty(obj, key, {
    value: val,
    enumerable: !!enume,
    writable: true,
    configurable: true
  });  
};

接下来,就是实现$set方法了,整体结构如下:

proxyObject(extendObj, '$set', function(key, val){
  //this指向extendObj
  if(this.hasOwnProperty(key)){
    return;
  }else{
    /*
     TODO:在extendObj中监听key属性,
     且,若key属性值为对象,再次监听key属性值
    */     
  }  
});

看到上面的TODO注释,是否似曾相识,不就是是在“模拟Vue之数据驱动2”遇见过的嘛,通过Observer.prototype.convert监听key属性,通过new Observer再次监听key属性值不就完啦。

的确,但是一旦这样做了,不就和上面我们提到的“直接将$set赋予监听对象”问题一样嘛,耦合性太大,且随着需求上涨,不易维护。

固而,在此需要一点小技巧:在observer模块中为每个监听对象赋予一个$Observer属性,其值指向Observer自身实例,如下:

//observer.js
p.walk = function(data){
  let keys = Object.keys(data);
  keys.forEach( key => {
    let val = data[key];
    if(typeof val === 'object'){
      new Observer(val);
    }
    this.convert(key, val);
  });
  //$Observer属性指向Observer自身实例
  data.$Observer = this;
}
//新增一个observe方法
p.observe = function(data){
  if(typeof data === 'object'){
    new Observer(data);  
  }  
}

好了,这样之后,得$set整体实现如下:

proxyObject(extendObj, '$set', function(key, val){
  if(this.hasOwnProperty(key)){
    return;
  }else{
    proxyObject(this, key, val, true);
    let ob = this.$Observer;
    ob.observe(val);
    ob.convert(key, val);  
  }  
});

到此,一个简单的$set方法构建完毕。

在上面我们提到,之所以需要一个恒定extendObj对象,是为了更好的代码管理。且,到目前为止,需要监听的对象上并没有扩展$set方法呢,所以,下面的事情就是为了达到以上效果,如下:

//observer.js
function Observer(data){
  if(!(this instanceof Observer)){
    return new Observer(data);
  }
  //将监听对象的隐指针指向我们的extendObj对象
  data.__proto__ = extendObj;
  this.data = data;
  this.walk(data);  
}

好了,一切完毕,接下来就测试下吧:

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

效果如下:

Vue数据驱动模拟实现3

Perfect,完整代码见github。

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

Javascript 相关文章推荐
js判断变量是否空值的代码
Oct 26 Javascript
jQuery+jRange实现滑动选取数值范围特效
Mar 14 Javascript
JS实现左右拖动改变内容显示区域大小的方法
Oct 13 Javascript
EasyUi combotree 实现动态加载树节点
Apr 01 Javascript
极力推荐10个短小实用的JavaScript代码段
Aug 03 Javascript
关于JavaScript和jQuery的类型判断详解
Oct 08 Javascript
Angular.JS内置服务$http对数据库的增删改使用教程
May 07 Javascript
一步步教会你微信小程序的登录鉴权
Apr 09 Javascript
在微信小程序里使用watch和computed的方法
Aug 02 Javascript
inquirer.js一个用户与命令行交互的工具详解
May 18 Javascript
JavaScript中交换值的10种方法总结
Aug 18 Javascript
Vue使用鼠标在Canvas上绘制矩形
Dec 24 Vue.js
jQuery实现判断控件是否显示的方法
Jan 11 #Javascript
jQuery Form表单取值的方法
Jan 11 #Javascript
vue实现ajax滚动下拉加载,同时具有loading效果(推荐)
Jan 11 #Javascript
浅谈JavaScript中promise的使用
Jan 11 #Javascript
JS多文件上传的实例代码
Jan 11 #Javascript
微信小程序开发(一) 微信登录流程详解
Jan 11 #Javascript
Javascript中return的使用与闭包详解
Jan 11 #Javascript
You might like
php获取mysql版本的几种方法小结
2008/03/25 PHP
PHP开发Apache服务器配置
2015/07/15 PHP
PHP实现的猴王算法(猴子选大王)示例
2018/04/30 PHP
PHP PDOStatement::nextRowset讲解
2019/02/01 PHP
jQuery使用手册之一
2007/03/24 Javascript
JavaScript 自动完成脚本整理(33个)
2009/10/20 Javascript
Jquery利用mouseenter和mouseleave实现鼠标经过弹出层且可以点击
2014/02/12 Javascript
JavaScript+html5 canvas制作的百花齐放效果完整实例
2016/01/26 Javascript
简单实现js间歇或无缝滚动效果
2016/06/29 Javascript
javascript表单控件实例讲解
2016/09/13 Javascript
Bootstrap CSS布局之表单
2016/12/17 Javascript
利用imgareaselect辅助后台实现图片上传裁剪
2017/03/02 Javascript
javascript 通过键名获取键盘的keyCode方法
2017/12/31 Javascript
JQuery常见节点操作实例分析
2019/05/15 jQuery
JS实现移动端可折叠导航菜单(现代都市风)
2020/07/07 Javascript
vuex存取值和映射函数使用说明
2020/07/24 Javascript
vue自定义树状结构图的实现方法
2020/10/18 Javascript
[05:31]干嘛呢兄弟!DOTA2 TI9语音轮盘部分出处
2019/05/14 DOTA
[38:32]完美世界DOTA2联赛循环赛 Forest vs DM 第二场 11.06
2020/11/06 DOTA
python算法学习之基数排序实例
2013/12/18 Python
Python随机生成彩票号码的方法
2015/03/05 Python
Python使用Flask框架获取当前查询参数的方法
2015/03/21 Python
Python利用公共键如何对字典列表进行排序详解
2018/05/19 Python
python3中zip()函数使用详解
2018/06/29 Python
TFRecord文件查看包含的所有Features代码
2020/02/17 Python
pytorch实现保证每次运行使用的随机数都相同
2020/02/20 Python
pytest fixtures装饰器的使用和如何控制用例的执行顺序
2021/01/28 Python
css3中的calc函数浅析
2018/07/10 HTML / CSS
详解Html5 Canvas画线有毛边解决方法
2018/03/01 HTML / CSS
乌克兰香水和化妆品网站:Notino.ua
2018/03/26 全球购物
向全球直邮输送天然健康产品:iHerb.com
2020/05/03 全球购物
System.Array.CopyTo()和System.Array.Clone()有什么区别
2016/06/20 面试题
社区十八大感言
2014/01/19 职场文书
2014年销售工作总结
2014/12/01 职场文书
初中信息技术教学计划
2015/01/22 职场文书
2016医师资格考试考生诚信考试承诺书
2016/03/25 职场文书