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 相关文章推荐
一份老外写的XMLHttpRequest代码多浏览器支持兼容性
Jan 11 Javascript
基于jQuery实现的当离开页面时出现提示的实现代码
Jun 27 Javascript
jquery的live使用注意事项
Feb 18 Javascript
jquery ztree实现下拉树形框使用到了json数据
May 14 Javascript
JS组件Bootstrap Table表格行拖拽效果实现代码
Aug 27 Javascript
Angularjs 实现分页功能及示例代码
Sep 14 Javascript
bootstrap datepicker限定可选时间范围实现方法
Sep 28 Javascript
JavaScript基础教程之如何实现一个简单的promise
Sep 11 Javascript
layui禁用侧边导航栏点击事件的解决方法
Sep 25 Javascript
vue data变量相互赋值后被实时同步的解决步骤
Aug 05 Javascript
浅谈vue-props的default写不写有什么区别
Aug 09 Javascript
JavaScript数组 几个常用方法总结
Nov 11 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
eAccelerator的安装与使用详解
2013/06/13 PHP
PHP实现基于栈的后缀表达式求值功能
2017/11/10 PHP
jquery向.ashx文件post中文乱码问题的解决方法
2011/03/28 Javascript
jquery鼠标滑过提示title具体实现代码
2013/08/06 Javascript
JS去除数组重复值的五种不同方法
2013/09/06 Javascript
js实现省市联动效果的简单实例
2014/02/10 Javascript
百度地图自定义控件分享
2015/03/04 Javascript
JavaScript原生对象之Date对象的属性和方法详解
2015/03/13 Javascript
JavaScript中用于四舍五入的Math.round()方法讲解
2015/06/15 Javascript
jQuery根据用户电脑是mac还是pc加载对应样式的方法
2015/06/26 Javascript
js实现简单排列组合的方法
2016/01/27 Javascript
jquery,js简单实现类似Angular.js双向绑定
2017/01/13 Javascript
微信小程序 侧滑删除(左滑删除)
2017/05/23 Javascript
React复制到剪贴板的示例代码
2017/08/22 Javascript
Node使用Sequlize连接Mysql报错:Access denied for user ‘xxx’@‘localhost’
2018/01/03 Javascript
JS计算两个数组的交集、差集、并集、补集(多种实现方式)
2019/05/21 Javascript
微信小程序实现的picker多级联动功能示例
2019/05/23 Javascript
jQuery操作选中select下拉框的值代码实例
2020/02/07 jQuery
[44:47]Ti4 循环赛第三日 iG vs NaVi
2014/07/12 DOTA
Python装饰器(decorator)定义与用法详解
2018/02/09 Python
Python Django 简单分页的实现代码解析
2019/08/21 Python
python json 递归打印所有json子节点信息的例子
2020/02/27 Python
python如何调用java类
2020/07/05 Python
python3.7.3版本和django2.2.3版本是否可以兼容
2020/09/01 Python
个人素质的自我评价分享
2013/12/16 职场文书
时尚休闲吧创业计划书
2014/01/25 职场文书
《恐龙》教学反思
2014/04/27 职场文书
大学活动总结范文
2014/04/29 职场文书
安全技术说明书
2014/05/09 职场文书
安全环保演讲稿
2014/08/28 职场文书
欢迎新生标语
2014/10/06 职场文书
合理化建议书
2015/02/04 职场文书
2015年药店店长工作总结
2015/04/29 职场文书
十一月早安语录:把心放轻,人生就是一朵自在的云
2019/11/04 职场文书
Vue.Draggable实现交换位置
2022/04/07 Vue.js
vue3语法糖内的defineProps及defineEmits
2022/04/14 Vue.js