Vue数据驱动模拟实现4


Posted in Javascript onJanuary 12, 2017

一、前言

在"模拟Vue之数据驱动3"中,我们实现了为每个对象扩展一个$set方法,用于新增属性使用,这样就可以监听新增的属性了。

当然,数组也是对象,也可以通过$set方法实现新增属性。

但是,对于数组而言,通常我们是通过push之类的方法吧。

PS:Vue中明确指出push、pop、shift、unshift、splice、sort、reverse方法为变异方法,可以通过它们监听属性变化,触发视图更新(详情见here)

下面,我们就一起来实现这些Array的变异方法吧。

注:我们将Array变异方法实现,也写在extendObj.js中的,因为数组也是对象嘛。

二、Array变异方法实现

要实现这些变异方法,毫无疑问,我们会重写它们,那在Array.prototype里面重写吗?

当然不是,这样不就影响了所有数组对象的原型链了么!

为了避免这种情况,且,我们只是想在监听数据对象上继承这些变异数组方法,那么细心的你会发现,其实与我们在"模拟Vue之数据驱动3"中实现$set方法类似了。

首先,我们创建arrKeys对象用于保存需要变异的数组方法以及恒定对象extendArr,如下:

let arrKeys = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'];
const extendArr = [];

接着,就是在extendArr对象上,一一监听arrKeys中的方法了,与$set方法类似,整体结构如下:

!function(){
  arrKeys.forEach(function(key){
    proxyObject(extendArr, key, function(){
      //TODO
    });
  });
}();

注:proxyObject方法其实核心就是Object.defineProperty,详见"模拟Vue之数据驱动3".

接下来,就是实现核心部分代码了,重写这些方法的目的,是为了监听数据变化,所以要在方法原有功能不变的情况下,重写它们,Array.xxx.apply即可实现原有功能。

且,push、unshift、splice这三个方法可以在原数组中,新增属性,故而,我们需要监听新增属性以及它们的属性值,这里就和$set方法完全一样了,通过$Observer,即可利用observe以及convert方法实现了。

实现代码如下:

!function(){
  arrKeys.forEach(function(key){
    proxyObject(extendArr, key, function(){
      console.log('Fun ' + key + ' is observed');
      let result;
      let arrProto = Array.prototype;
      let ob = this.$Observer;
      let arr = arrProto.slice.call(arguments);
      let inserted;
      let index;
      switch(key){
        case 'push': {
          inserted = arr;
          index = this.length;
          break;
        }
        case 'unshift': {
          inserted = arr;
          index = 0;
          break;
        }
        case 'splice': {
          inserted = arr.slice(2);
          index = arr[0];
          break;
        }
      }
      result = arrProto[key].apply(this, arguments);
      if(inserted){
        inserted.forEach(val => {
          ob.observe(val);
          ob.convert(index++, val);
        });
      }
      return result;
    });
  });
}();

最后,就是在需要监听的对象上继承这些变异方法咯,如下:

//observer.js
function Observer(data){
  if(!(this instanceof Observer)){
    return new Observer(data);
  }
  data.__proto__ = extendObj;
  //继承变异方法push、pop等等
  if(Array.isArray(data)){
    data.__proto__.__proto__ = extendArr;
  }
  this.data = data;
  this.walk(data);  
}

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

<script src="./extendObj.js"></script>
<script src="./observer.js"></script>
<script>
  'use strict';
  let data = {
    msg: [5, 2, 0],
    user: {
      name: 'Monkey',
      age: 24
    },
    lover: {
      name: 'Dorie',
      age: 23
    }
  };
  Observer(data);
</script>

效果如下:

Vue数据驱动模拟实现4

Perfect,此时,你可能会想,数组方法中仅有push、unshift、splice会为数组新增属性,那么我们又何必将其他方法,例如sort、reverse重写呢,也没发现有什么猫腻呢?

不错,在此时,并没有什么卵用,但是,你要知道sort、reverse等这些方法,可是会引起数组变化的,那么就会影响视图展现,这些变化,又怎么通知数组呢?就是下篇随笔会具体说明的。

该篇随笔代码,详情见github.

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

Javascript 相关文章推荐
Javascript的IE和Firefox兼容性汇编(zz)
Feb 02 Javascript
jquery怎样实现ajax联动框(二)
Mar 08 Javascript
优化javascript的执行效率一些方法总结
Dec 25 Javascript
基于javascript实现页面加载loading效果
Sep 15 Javascript
Angular.JS判断复选框checkbox是否选中并实时显示
Nov 30 Javascript
详谈js中window.location.search的用法和作用
Feb 13 Javascript
jsonp跨域请求实现示例
Mar 13 Javascript
详解Angular调试技巧之报错404(not found)
Jan 31 Javascript
JavaScript获取移动设备型号的实现代码(JS获取手机型号和系统)
Mar 10 Javascript
基于Angularjs-router动态改变Title值的问题
Aug 30 Javascript
微信JS-SDK updateAppMessageShareData安卓不能自定义分享详解
Mar 29 Javascript
简单了解vue 插值表达式Mustache
Jul 22 Javascript
移动端点击态处理的三种实现方式
Jan 12 #Javascript
js手机号批量滚动抽奖实现代码
Apr 17 #Javascript
js图片轮播手动切换特效
Jan 12 #Javascript
原生js实现倒计时功能(多种格式调用)
Jan 12 #Javascript
JavaScript定义全局对象的方法示例
Jan 12 #Javascript
Node.js制作简单聊天室
Jan 12 #Javascript
jQuery 插件实现随机自由弹跳气泡样式
Jan 12 #Javascript
You might like
php中文本数据翻页(留言本翻页)
2006/10/09 PHP
如何在PHP中进行身份认证
2006/10/09 PHP
PHP中for循环语句的几种变型
2007/03/16 PHP
PHP创建文件,并向文件中写入数据,覆盖,追加的实现代码
2016/03/25 PHP
Yii的Srbac插件用法详解
2016/07/14 PHP
php+jQuery ajax实现的实时刷新显示数据功能示例
2019/09/12 PHP
斜45度寻路实现函数
2009/08/20 Javascript
为JS扩展Array.prototype.indexOf引发的问题及解决办法
2015/01/21 Javascript
jQuery实现带水平滑杆的焦点图动画插件
2016/03/08 Javascript
JQuery 动态生成Table表格实例代码
2016/12/02 Javascript
JS实现的input选择图片本地预览功能示例
2018/08/29 Javascript
jQuery中DOM操作原则实例分析
2019/08/01 jQuery
解决layui的table插件无法多层级获取json数据的问题
2019/09/19 Javascript
vue实现导航菜单和编辑文本的示例代码
2020/07/04 Javascript
python多线程用法实例详解
2015/01/15 Python
浅析python打包工具distutils、setuptools
2018/04/20 Python
python通过ffmgep从视频中抽帧的方法
2018/12/05 Python
python pandas移动窗口函数rolling的用法
2020/02/29 Python
python中安装django模块的方法
2020/03/12 Python
纯CSS3实现8组超炫酷鼠标滑过图片动画
2016/03/16 HTML / CSS
澳大利亚运动鞋零售商:The Athlete’s Foot
2018/11/04 全球购物
Omio葡萄牙:全欧洲低价大巴、火车和航班搜索和比价
2019/02/09 全球购物
英国Iceland杂货店:网上食品购物
2020/12/16 全球购物
亚马逊意大利站点:Amazon.it
2020/12/31 全球购物
道德模范先进事迹
2014/02/14 职场文书
高中生学期学习自我评价
2014/02/24 职场文书
书香家庭事迹材料
2014/05/09 职场文书
工商局局长个人对照检查材料思想汇报
2014/09/23 职场文书
申报材料格式
2014/12/30 职场文书
苦儿流浪记读书笔记
2015/07/01 职场文书
七夕情人节问候语
2015/11/11 职场文书
协议书格式模板
2016/03/24 职场文书
MySQL数据库压缩版本安装与配置详细教程
2021/05/21 MySQL
Linux中Nginx的防盗链和优化的实现代码
2021/06/20 Servers
《游戏王:大师决斗》新活动上线 若无符合卡组可免费租用
2022/04/13 其他游戏
Python中的 No Module named ***问题及解决
2022/07/23 Python