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实现改变TEXTAREA滚动条和按钮的颜色,以及怎样让滚动条变得扁平
Apr 20 Javascript
jQuery学习之prop和attr的区别示例介绍
Nov 15 Javascript
jQuery实现视频作为全屏幕背景
Dec 18 Javascript
jQuery实现按钮只点击一次后就取消点击事件绑定的方法
Jun 26 Javascript
JS基于VML技术实现的五角星礼花效果代码
Oct 26 Javascript
JavaScript常用正则函数用法示例
Jan 23 Javascript
js实现抽奖效果
Mar 27 Javascript
基于Vue中点击组件外关闭组件的实现方法
Mar 06 Javascript
Vue使用json-server进行后端数据模拟功能
Apr 17 Javascript
vue :src 文件路径错误问题的解决方法
May 15 Javascript
详解小程序毫秒级倒计时(适用于拼团秒杀功能)
May 05 Javascript
javascript 函数的暂停和恢复实例详解
Apr 25 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
安装APACHE
2007/01/15 PHP
PHP+jQuery 注册模块开发详解
2014/10/14 PHP
PHP清除数组中所有字符串两端空格的方法
2014/10/20 PHP
php通过array_shift()函数移除数组第一个元素的方法
2015/03/18 PHP
PHP  实现等比压缩图片尺寸和大小实例代码
2016/10/08 PHP
Linux服务器下PHPMailer发送邮件失败的问题解决
2017/03/04 PHP
yii2.0整合阿里云oss上传单个文件的示例
2017/09/19 PHP
PHP序列化的四种实现方法与横向对比
2018/11/29 PHP
PHP实现简单登录界面
2019/10/23 PHP
JS遮罩层效果 兼容ie firefox jQuery遮罩层
2010/07/26 Javascript
跟我学Nodejs(二)--- Node.js事件模块
2014/05/21 NodeJs
JavaScript中的闭包(Closure)详细介绍
2014/12/30 Javascript
Javascript中的包装类型介绍
2015/04/02 Javascript
深入学习JavaScript的AngularJS框架中指令的使用方法
2016/03/05 Javascript
微信小程序开发中的疑问解答汇总
2017/07/03 Javascript
Javascript中toFixed计算错误(依赖银行家舍入法的缺陷)解决方法
2017/08/22 Javascript
基于jQuery实现的单行公告活动轮播效果
2017/08/23 jQuery
vue解决一个方法同时发送多个请求的问题
2018/09/25 Javascript
mpvue 单文件页面配置详解
2018/12/02 Javascript
Python的time模块中的常用方法整理
2015/06/18 Python
python实现简单神经网络算法
2018/03/10 Python
Python+OpenCV实现车牌字符分割和识别
2018/03/31 Python
PyQt5每天必学之工具提示功能
2018/04/19 Python
Django 5种类型Session使用方法解析
2020/04/29 Python
python基于Kivy写一个图形桌面时钟程序
2021/01/28 Python
New Balance德国官方网站:购买鞋子和服装
2019/08/31 全球购物
牛津在线药房:Oxford Online Pharmacy
2020/11/16 全球购物
静态成员和非静态成员的区别
2012/05/12 面试题
个人简历自我评价八例
2013/10/31 职场文书
客服服务心得体会
2013/12/30 职场文书
有子女的离婚协议书怎么写(范本)
2014/09/29 职场文书
2014年质检员工作总结
2014/11/18 职场文书
社区国庆节活动总结
2015/03/23 职场文书
2015年学校心理健康教育工作总结
2015/05/11 职场文书
交通事故协议书范本
2016/03/19 职场文书