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 获取链接(url)参数的方法
Feb 15 Javascript
jQuery 美元符冲突的解决方法
Mar 28 Javascript
检测jQuery.js是否已加载的判断代码
May 20 Javascript
JQuery模板插件 jquery.tmpl 动态ajax扩展
Nov 10 Javascript
FF火狐下获取一个元素同类型的相邻元素实现代码
Dec 15 Javascript
使用ajaxfileupload.js实现ajax上传文件php版
Jun 26 Javascript
JS仿Windows开机启动Loading进度条的方法
Feb 26 Javascript
JavaScript实现按照指定长度为数字前面补零输出的方法
Mar 19 Javascript
js判断子窗体是否关闭的方法
Aug 11 Javascript
浅析Javascript匿名函数与自执行函数
Feb 06 Javascript
微信小程序中的swiper组件详解
Apr 14 Javascript
Vue+Element-U实现分页显示效果
Nov 15 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读取TXT文件向数据库导入海量数据的方法
2013/04/23 PHP
一个好用的PHP验证码类实例分享
2013/12/27 PHP
php调用shell的方法
2014/11/05 PHP
详解Yii2 定制表单输入字段的标签和样式
2017/01/04 PHP
PHP实现的分解质因数操作示例
2018/08/01 PHP
Alliance vs Liquid BO3 第二场2.13
2021/03/10 DOTA
URI、URL和URN之间的区别与联系
2006/12/20 Javascript
js中传递特殊字符(+,&amp;)的方法
2014/01/16 Javascript
jQuery实现锚点scoll效果实例分析
2015/03/10 Javascript
JavaScript DOM基础
2015/04/13 Javascript
js实现Select头像选择实时预览代码
2015/08/17 Javascript
如何利用AngularJS打造一款简单Web应用
2015/12/05 Javascript
js针对ip地址、子网掩码、网关的逻辑性判断
2016/01/06 Javascript
实现React单页应用的方法详解
2016/08/02 Javascript
利用Javascript仿Excel的数据透视分析功能
2016/09/07 Javascript
jQuery UI制作选项卡(tabs)
2016/12/13 Javascript
js 作用域和变量详解
2017/02/16 Javascript
nodejs 图解express+supervisor+ejs的用法(推荐)
2017/09/08 NodeJs
简单两步使用node发送qq邮件的方法
2019/03/01 Javascript
vue 自定指令生成uuid滚动监听达到tab表格吸顶效果的代码
2020/09/16 Javascript
ajax jquery实现页面某一个div的刷新效果
2021/03/04 jQuery
Python返回数组/List长度的实例
2018/06/23 Python
python保存网页图片到本地的方法
2018/07/24 Python
Python列表切片操作实例总结
2019/02/19 Python
在Qt中正确的设置窗体的背景图片的几种方法总结
2019/06/19 Python
pandas数据拼接的实现示例
2020/04/16 Python
AmazeUI 点击元素显示全屏的实现
2020/08/25 HTML / CSS
英国广泛的照明产品网站:Lights4living
2018/01/28 全球购物
【魔兽争霸3重制版】原版画面与淬火MOD画面对比
2021/03/26 魔兽争霸
大学毕业生个人自荐信范文
2014/01/08 职场文书
党的群众路线教育实践活动通讯稿
2014/09/10 职场文书
2015年药店店长工作总结
2015/04/29 职场文书
文艺部部长竞选稿
2015/11/21 职场文书
python实战之一步一步教你绘制小猪佩奇
2021/04/22 Python
Python pyecharts绘制条形图详解
2022/04/02 Python
PyTorch中permute的使用方法
2022/04/26 Python