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版本A*寻路算法
Dec 22 Javascript
Jquery实现显示和隐藏的4种简单方式
Aug 28 Javascript
jQuery图片轮播的具体实现
Sep 11 Javascript
jQuery对象的length属性用法实例
Dec 27 Javascript
jQuery动态添加
Apr 07 Javascript
jQuery倒计时代码(超简单)
Feb 27 Javascript
JavaScript判断浏览器和hack滚动条的写法
Jul 23 Javascript
AngularJS实时获取并显示密码的方法
Feb 06 Javascript
JS实现数组的增删改查操作示例
Aug 29 Javascript
详解如何构建Promise队列实现异步函数顺序执行
Oct 23 Javascript
简单使用webpack打包文件的实现
Oct 29 Javascript
JavaScript 去重和重复次数统计
Mar 31 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
php中数组首字符过滤功能代码
2012/07/31 PHP
PHP可变函数的使用详解
2013/06/14 PHP
PHP中鲜为人知的10个函数
2014/02/28 PHP
ThinkPHP表单令牌错误的相关解决方法分析
2016/05/20 PHP
Extjs4 GridPanel的主要配置参数详细介绍
2013/04/18 Javascript
将nodejs打包工具整合到鼠标右键的方法
2013/05/11 NodeJs
简单的ajax连接库分享(不用jquery的ajax)
2014/01/19 Javascript
jQuery EasyUI封装简化操作
2016/09/18 Javascript
微信小程序 富文本转文本实例详解
2016/10/24 Javascript
使用requirejs模块化开发多页面一个入口js的使用方式
2017/06/14 Javascript
layer弹出层父子页面事件相互调用方法
2018/08/17 Javascript
JSON生成Form表单的方法示例
2018/11/21 Javascript
Vue动画事件详解及过渡动画实例
2019/02/09 Javascript
详谈vue中router-link和传统a链接的区别
2020/07/22 Javascript
vue用elementui写form表单时,在label里添加空格操作
2020/08/13 Javascript
简单谈谈offsetleft、offsetTop和offsetParent
2020/12/04 Javascript
[43:32]Winstrike vs VGJ.S 2018国际邀请赛淘汰赛BO3 第一场 8.23
2018/08/24 DOTA
Python实现计算文件夹下.h和.cpp文件的总行数
2015/04/23 Python
Python+django实现文件上传
2016/01/17 Python
PyChar学习教程之自定义文件与代码模板详解
2017/07/17 Python
Python实现读取邮箱中的邮件功能示例【含文本及附件】
2017/08/05 Python
Python3实现获取图片文字里中文的方法分析
2018/12/13 Python
Python3 关于pycharm自动导入包快捷设置的方法
2019/01/16 Python
Django 配置多站点多域名的实现步骤
2019/05/17 Python
python RC4加密操作示例【测试可用】
2019/09/26 Python
使用python执行shell脚本 并动态传参 及subprocess的使用详解
2020/03/06 Python
利用 CSS3 实现的无缝轮播功能代码
2017/09/25 HTML / CSS
HTML5之消息通知的使用(Web Notification)
2018/10/30 HTML / CSS
微软美国官方网站:Microsoft美国
2018/05/10 全球购物
合伙经营协议书范本
2014/04/18 职场文书
2014小学教师个人工作总结
2014/11/10 职场文书
安全员岗位职责
2015/02/10 职场文书
父亲节寄语大全
2015/02/27 职场文书
违纪学生保证书
2015/02/27 职场文书
Java实现简易的分词器功能
2021/06/15 Java/Android
Python爬虫入门案例之爬取去哪儿旅游景点攻略以及可视化分析
2021/10/16 Python