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 相关文章推荐
Javascript字符串对象的常用方法简明版
Jun 26 Javascript
js时间日期格式化封装函数
Dec 02 Javascript
JQuery设置时间段下拉选择实例
Dec 30 Javascript
基于JavaScript实现生成名片、链接等二维码
Sep 20 Javascript
Javascript ES6中对象类型Sets的介绍与使用详解
Jul 17 Javascript
axios全局注册,设置token,以及全局设置url请求网段的方法
Sep 25 Javascript
vue-cli3+typescript初体验小结
Feb 28 Javascript
小程序实现悬浮搜索框
Jul 12 Javascript
使用VUE实现在table中文字信息超过5个隐藏鼠标移到时弹窗显示全部
Sep 16 Javascript
VUE实现图片验证码功能
Nov 18 Javascript
vscode 使用Prettier插件格式化配置使用代码详解
Aug 10 Javascript
vue使用screenfull插件实现全屏功能
Sep 17 Javascript
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
Discuz! 5.0.0论坛程序中加入一段js代码,让会员点击下载附件前自动弹出提示窗口
2007/04/18 PHP
php三种实现多线程类似的方法
2015/10/30 PHP
PHP中让json_encode不自动转义斜杠“/”的方法
2017/02/28 PHP
JS数学函数Exp使用说明
2012/08/09 Javascript
javaScript arguments 对象使用介绍
2013/10/18 Javascript
jquery防止重复执行动画避免页面混乱
2014/04/22 Javascript
jQuery移除tr无效的解决方法(tr是动态添加)
2014/09/22 Javascript
JS实现很酷的EMAIL地址添加功能实例
2015/02/28 Javascript
JavaScript简介_动力节点Java学院整理
2017/06/26 Javascript
jQuery 改变P标签文本值方法
2018/02/24 jQuery
JavaScript常用数学函数用法示例
2018/05/14 Javascript
JS实现自定义弹窗功能
2018/08/08 Javascript
移动端图片上传旋转、压缩问题的方法
2018/10/16 Javascript
vue-lazyload使用总结(推荐)
2018/11/01 Javascript
JS实现处理时间,年月日,星期的公共方法示例
2019/05/31 Javascript
解析vue、angular深度作用选择器
2019/09/11 Javascript
使用 JavaScript 创建并下载文件(模拟点击)
2019/10/25 Javascript
微信jssdk踩坑之签名错误invalid signature
2020/05/19 Javascript
如何利用JavaScript编写更好的条件语句详解
2020/08/10 Javascript
一起深入理解js中的事件对象
2021/02/06 Javascript
[01:18]PWL开团时刻DAY10——一拳超人
2020/11/11 DOTA
[01:08:56]DOTA2-DPC中国联赛 正赛 Magma vs LBZS BO3 第一场 2月7日
2021/03/11 DOTA
通过C++学习Python
2015/01/20 Python
Python的装饰器模式与面向切面编程详解
2015/06/21 Python
对Python中9种生成新对象的方法总结
2018/05/23 Python
Python 中字符串拼接的多种方法
2018/07/30 Python
python自动化测试之DDT数据驱动的实现代码
2019/07/23 Python
python实现发送form-data数据的方法详解
2019/09/27 Python
Banana Republic欧盟:美国都市简约风格的代表品牌
2018/05/09 全球购物
SQL Server面试题
2016/10/17 面试题
幼师个人总结范文
2015/02/28 职场文书
推荐信范文大全
2015/03/27 职场文书
离婚协议书范文2016
2016/03/18 职场文书
党员公开承诺书(2016最新版)
2016/03/24 职场文书
只需要12页,掌握撰写一流商业计划书的技巧
2019/05/07 职场文书
PyTorch device与cuda.device用法
2022/04/03 Python