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 相关文章推荐
短信提示使用 特效
Jan 19 Javascript
JS数组的赋值介绍
Mar 10 Javascript
ClearTimeout消除闪动实例代码
Feb 29 Javascript
DWR中各种java方法的调用
May 04 Javascript
jsp 网站引入外部css或者js失效问题解决
Oct 31 Javascript
laydate如何根据开始时间或者结束时间限制范围
Nov 15 Javascript
ES10 特性的完整指南小结
Mar 04 Javascript
JS实现提示框跟随鼠标移动
Aug 27 Javascript
Vue axios 将传递的json数据转为form data的例子
Oct 29 Javascript
js+css3实现炫酷时钟
Aug 18 Javascript
JavaScript判断数据类型有几种方法及区别介绍
Sep 02 Javascript
Vuex实现简单购物车
Jan 10 Vue.js
移动端点击态处理的三种实现方式
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
模拟OICQ的实现思路和核心程序(一)
2006/10/09 PHP
php数据库抽象层 PDO
2011/05/07 PHP
php中array_slice和array_splice函数解析
2016/10/18 PHP
阿里对象存储OSS在laravel框架中的使用方法
2019/10/13 PHP
javascript 兼容FF的onmouseenter和onmouseleave的代码
2008/07/19 Javascript
jQuery 使用手册(七)
2009/09/23 Javascript
div层的移动及性能优化
2010/11/16 Javascript
客户端js判断文件类型和文件大小即限制上传大小
2013/11/20 Javascript
经过绑定元素时会多次触发mouseover和mouseout事件
2014/02/28 Javascript
纯css下拉菜单 无需js
2016/08/15 Javascript
详解堆的javascript实现方法
2016/11/29 Javascript
Ionic 2 实现列表滑动删除按钮的方法
2017/01/22 Javascript
Angular指令封装jQuery日期时间插件datetimepicker实现双向绑定示例
2017/01/22 Javascript
Vue 组件间的样式冲突污染
2017/08/31 Javascript
jQuery幻灯片插件owlcarousel参数说明中文文档
2018/02/27 jQuery
Vue修改项目启动端口号方法
2019/11/07 Javascript
vue+echarts实现动态折线图的方法与注意
2020/09/01 Javascript
[00:14]护身甲盾
2019/03/06 DOTA
利用python获取当前日期前后N天或N月日期的方法示例
2017/07/30 Python
Python编程实现双链表,栈,队列及二叉树的方法示例
2017/11/01 Python
Python反转序列的方法实例分析
2018/03/21 Python
python 内置函数汇总详解
2019/09/16 Python
python读取csv文件指定行的2种方法详解
2020/02/13 Python
python os模块在系统管理中的应用
2020/06/22 Python
Python爬取微信小程序通用方法代码实例详解
2020/09/29 Python
用Python自动清理电脑内重复文件,只要10行代码(自动脚本)
2021/01/09 Python
python 求两个向量的顺时针夹角操作
2021/03/04 Python
Trina Turk官网:美国时装和泳装品牌
2018/06/10 全球购物
联想英国官网:Lenovo英国
2019/07/17 全球购物
应届生求职信写作技巧
2013/10/24 职场文书
大学生求职信例文
2014/06/29 职场文书
党风廉政建设调研报告
2015/01/01 职场文书
多人股份制合作协议书
2016/03/19 职场文书
python中requests库+xpath+lxml简单使用
2021/04/29 Python
css3 文字断裂效果
2022/04/22 HTML / CSS
Django框架中视图的用法
2022/06/10 Python