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 相关文章推荐
浏览器无法运行JAVA脚本的解决方法
Jan 09 Javascript
IE6/7 and IE8/9/10(IE7模式)依次隐藏具有absolute或relative的父元素和子元素后再显示父元素
Jul 31 Javascript
JS正则中的RegExp对象对象
Nov 07 Javascript
jQuery function的正确书写方法
Aug 02 Javascript
基于JQuery实现的图片自动进行缩放和裁剪处理
Jan 31 Javascript
详解JavaScript语法对{}处理的坑爹之处
Jun 05 Javascript
javascript中为某个元素指定事件的三种方式
Aug 07 Javascript
jQuery定义插件的方法
Dec 18 Javascript
javascript设计模式之策略模式学习笔记
Feb 15 Javascript
angularjs实现猜大小功能
Oct 23 Javascript
jquery实现弹窗(系统提示框)效果
Dec 10 jQuery
vue中配置scss全局变量的步骤
Dec 28 Vue.js
移动端点击态处理的三种实现方式
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动态分页函数,PHP开发分页必备啦
2011/11/07 PHP
php利用cookies实现购物车的方法
2014/12/10 PHP
php保存任意网络图片到服务器的方法
2015/04/14 PHP
JavaScript高级程序设计 阅读笔记(十二) js内置对象Math
2012/08/14 Javascript
JS TextArea字符串长度限制代码集合
2012/10/31 Javascript
addEventListener和attachEvent二者绑定的执行函数中的this不相同
2012/12/09 Javascript
JavaScript获取多个数组的交集简单实例
2013/11/11 Javascript
Array栈方法和队列方法的特点说明
2014/01/24 Javascript
node.js中的fs.lchown方法使用说明
2014/12/16 Javascript
JS实现网页标题栏显示当前时间和日期的完整代码
2015/11/02 Javascript
jQuery实现模仿微博下拉滚动条加载数据效果
2015/12/25 Javascript
JavaScript的removeChild()函数用法详解
2015/12/27 Javascript
JavaScript正则表达式exec/g实现多次循环用法示例
2017/01/17 Javascript
小程序开发实战:实现九宫格界面的导航的代码实现
2017/01/19 Javascript
AngularJS中的拦截器实例详解
2017/04/07 Javascript
Vue实现双向数据绑定
2017/05/03 Javascript
JS 60秒后重新发送验证码的实例讲解
2017/07/26 Javascript
JS实现调用本地摄像头功能示例
2018/05/18 Javascript
vue 国际化 vue-i18n 双语言 语言包
2018/06/07 Javascript
JS获取子节点、父节点和兄弟节点的方法实例总结
2018/07/06 Javascript
微信小程序页面缩放式侧滑效果的实现代码
2018/11/15 Javascript
详解用JS添加和删除class类名
2019/03/25 Javascript
全面了解Nginx, WSGI, Flask之间的关系
2018/01/09 Python
Python通用函数实现数组计算的方法
2019/06/13 Python
python进行OpenCV实战之画图(直线、矩形、圆形)
2020/08/27 Python
纯css3显示隐藏一个div特效的具体实现
2014/02/10 HTML / CSS
CSS3圆角和渐变2种常用功能详解
2016/01/06 HTML / CSS
美国婚礼礼品网站:MyWeddingFavors
2018/09/26 全球购物
法国在线药房:1001Pharmacies
2021/03/07 全球购物
优秀大学生求职自荐信范文
2014/04/19 职场文书
中学生励志演讲稿
2014/04/26 职场文书
巾帼志愿者活动方案
2014/08/17 职场文书
2015年新学期寄语
2015/02/26 职场文书
MySQL 用 limit 为什么会影响性能
2021/09/15 MySQL
用python基于appium模块开发一个自动收取能量的小助手
2021/09/25 Python
用Python实现屏幕截图详解
2022/01/22 Python