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 相关文章推荐
Jquery 设置标题的自动翻转
Oct 03 Javascript
JQuery学习笔录 简单的JQuery
Apr 09 Javascript
js购物车实现思路及代码(个人感觉不错)
Dec 23 Javascript
利用浏览器全屏api实现js全屏
Jan 16 Javascript
用javascript替换URL中的参数值示例代码
Jan 27 Javascript
JQuery中使用ajax传输超大数据的解决方法
Jul 14 Javascript
Javascript前端UI框架Kit使用指南之kitjs的对话框组件
Nov 28 Javascript
node.js入门实例helloworld详解
Dec 23 Javascript
js使用Replace结合正则替换重复出现的字符串功能示例
Dec 27 Javascript
jQuery实现获取table中鼠标click点击位置行号与列号的方法
Oct 09 jQuery
基于javascript实现碰撞检测
Mar 12 Javascript
关于Js中new操作符的作用详解
Feb 21 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实现模仿socket请求返回页面的方法
2014/11/04 PHP
主流PHP框架的优缺点对比分析
2014/12/25 PHP
php实现的数字验证码及数字运算验证码
2015/07/30 PHP
PHP实现深度优先搜索算法(DFS,Depth First Search)详解
2017/09/16 PHP
PHP中str_split()函数的用法讲解
2019/04/11 PHP
PHP面向对象程序设计之构造方法和析构方法详解
2019/06/13 PHP
你所要知道JS(DHTML)中的一些技巧
2007/01/09 Javascript
懒就要懒到底——鼠标自动点击(含时间判断)
2007/02/20 Javascript
js 禁用只读文本框获得焦点时的退格键
2010/04/25 Javascript
StringTemplate遇见jQuery冲突的解决方法
2011/09/22 Javascript
详解JavaScript语法对{}处理的坑爹之处
2014/06/05 Javascript
jQuery实现ajax调用WCF服务的方法(附带demo下载)
2015/12/04 Javascript
javascript HTML5 canvas实现打砖块游戏
2020/06/18 Javascript
Angular.js中$apply()和$digest()的深入理解
2016/10/13 Javascript
基于JavaScript实现瀑布流效果
2017/03/29 Javascript
使用 NodeJS+Express 开发服务端的简单介绍
2017/04/07 NodeJs
微信小程序 动画的简单实例
2017/10/12 Javascript
在Vue中使用HOC模式的实现
2020/08/23 Javascript
vue3.0生命周期的示例代码
2020/09/24 Javascript
vue 解决mintui弹窗弹起来,底部页面滚动bug问题
2020/11/12 Javascript
[05:01]3.19DOTA2发布会 我们都是刀塔人
2014/03/25 DOTA
python使用PyGame绘制图像并保存为图片文件的方法
2015/04/24 Python
在Python中操作时间之tzset()方法的使用教程
2015/05/22 Python
浅谈python类属性的访问、设置和删除方法
2016/07/25 Python
Python排序搜索基本算法之冒泡排序实例分析
2017/12/09 Python
python 将数据保存为excel的xls格式(实例讲解)
2018/05/03 Python
Python使用combinations实现排列组合的方法
2018/11/13 Python
python画双y轴图像的示例代码
2019/07/07 Python
Python函数的定义方式与函数参数问题实例分析
2019/12/26 Python
python GUI库图形界面开发之PyQt5美化窗体与控件(异形窗体)实例
2020/02/25 Python
Python的历史与优缺点整理
2020/05/26 Python
浅析Python面向对象编程
2020/07/10 Python
使用OpenCV实现道路车辆计数的使用方法
2020/07/15 Python
亚洲最大旅游体验平台:KKday
2017/10/21 全球购物
中学生旷课检讨书500字
2014/10/29 职场文书
房产销售员2015年终工作总结
2015/10/22 职场文书