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 相关文章推荐
中国地区三级联动下拉菜单效果分析
Nov 15 Javascript
javascript如何判断输入的url是否正确
Apr 11 Javascript
js获取时间并实现字符串和时间戳之间的转换
Jan 05 Javascript
JS实现从顶部下拉显示的带动画QQ客服特效代码
Oct 24 Javascript
input点击后placeholder中的提示消息消失
Jan 15 Javascript
jQuery插件EasyUI实现Layout框架页面中弹出窗体到最顶层效果(穿越iframe)
Aug 05 Javascript
javascript 网页进度条简单实例
Feb 22 Javascript
javascript深拷贝的原理与实现方法分析
Apr 10 Javascript
使用vue框架 Ajax获取数据列表并用BootStrap显示出来
Apr 24 Javascript
详解vue.js的事件处理器v-on:click
Jun 27 Javascript
element-ui中select组件绑定值改变,触发change事件方法
Aug 24 Javascript
jQuery实现判断滚动条滚动到document底部的方法分析
Aug 27 jQuery
移动端点击态处理的三种实现方式
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 session 预定义数组
2009/03/16 PHP
php 生成自动创建文件夹并上传文件的示例代码
2014/03/07 PHP
PHP实现获取域名的方法小结
2014/11/05 PHP
php metaphone()函数及php localeconv() 函数实例解析
2016/05/15 PHP
php array_values 返回数组的值实例详解
2016/11/17 PHP
JS模板实现方法
2013/04/03 Javascript
在表单提交前进行验证的几种方式整理
2013/07/31 Javascript
jquery阻止冒泡事件使用模拟事件
2013/09/06 Javascript
JavaScript中setInterval的用法总结
2013/11/20 Javascript
jquery常用方法及使用示例汇总
2014/11/08 Javascript
jQuery遍历json中多个map的方法
2015/02/12 Javascript
jQuery图片特效插件Revealing实现拉伸放大
2015/04/22 Javascript
使用AngularJS实现可伸缩的页面切换的方法
2015/06/19 Javascript
AngularJs解决跨域问题案例详解(简单方法)
2016/05/19 Javascript
简单实现jQuery多选框功能
2017/01/09 Javascript
vue2中引用及使用 better-scroll的方法详解
2018/11/15 Javascript
使用Phantomjs和Node完成网页的截屏快照的方法
2019/07/16 Javascript
Vue 中 a标签上href无法跳转的解决方式
2019/11/12 Javascript
JavaScript的console命令使用实例
2019/12/03 Javascript
python+matplotlib绘制简单的海豚(顶点和节点的操作)
2018/01/02 Python
Django跨域请求问题的解决方法示例
2018/06/16 Python
Python合并多个Excel数据的方法
2018/07/16 Python
基于Django框架利用Ajax实现点赞功能实例代码
2018/08/19 Python
Python爬虫 批量爬取下载抖音视频代码实例
2019/08/16 Python
暇步士官网:Hush Puppies
2016/09/22 全球购物
美国知名的家庭连锁百货商店:Boscov’s
2017/07/27 全球购物
英国床和浴室商场:Bed & Bath Emporium
2018/05/20 全球购物
国际贸易专业推荐信
2013/11/15 职场文书
专升本个人自我评价
2013/12/22 职场文书
2014婚礼司仪主持词
2014/03/14 职场文书
2014世界杯球队球队口号
2014/06/05 职场文书
2016年中秋节晚会领导致辞
2015/11/26 职场文书
《大禹治水》教学反思
2016/02/22 职场文书
python引入其他文件夹下的py文件具体方法
2021/05/23 Python
Django Paginator分页器的使用示例
2021/06/23 Python
使用python将HTML转换为PDF pdfkit包(wkhtmltopdf) 的使用方法
2022/04/21 Python