浅谈Vue数据响应思路之数组


Posted in Javascript onNovember 06, 2018

之前梳理Vue数据响应思路 时没有考虑数组的情况。

js 中数组有很多实例方法,其中有一部分会改变数组本身的值,比如 push pop shift unshift 等,这些方法被称为变异方法,这些变异方法也是 Vue 开发中常用的数组操作方法。那么要实现对数组的观测,首先要考虑的就是如何截获这些变异方法的调用。

简单来说,Vue 是通过保持这些数组变异方法原有功能不变的前提下,对其功能进行扩展来实现拦截的。具体怎么操作,可以先看一下例子:

function add10(num) {
  return num + 10
}
console.log(add10(5)) // 15

const originalAdd10 = add10
add10 = function(num) {
  console.log('截获了add10操作')
  return originalAdd10(num)
}
console.log(add10(5)) // '截获了add10操作'
           // 15

该例中,首先使用变量 originalAdd10 缓存 add10 函数,再重新定义 add10 函数,在重新定义的函数体里就可以执行额外增加的功能,比如上例中的 console.log('截获了add10操作'),然后执行缓存的 add10 函数即 originalAdd10,并将结果返回,原理大抵如此。

那么,具体可实现如下:

const mutationMethods = [
 'push',
 'pop',
 'shift',
 'unshift',
 'splice',
 'sort',
 'reverse'
]
const arrayMethods = Object.create(Array.prototype)
const arrayProto = Array.prototype

mutationMethods.forEach(method => {
 arrayMethods[method] = function (...args) {
  const result = arrayProto[method].apply(this, args)
  console.log(`我截获了对数组的${method}操作`)
  return result
 }
})

const arr = ['kobe', 'jordan']
arr.__proto__ = arrayMethods

arr.push('harden') // '我截获了对数组的push操作'
console.log(JSON.stringify(arr)) // '["kobe","jordan","harden"]'

以上,mutationMethods 是所有要拦截的数组变异方法的集合。

整体思路就是通过设置数组对象的 __proto__ 属性的值为一个新对象 arrayMethods,以代理数组 mutationMethods 中的变异方法,并将 arrayMethods 的原型设置为数组构造函数本来的原型,这样方能保证除却代理的方法以外,不影响数组本身的其它方法和属性。

其中:

const arrayMethods = Object.create(Array.prototype)

以上实现了 arrayMethods 的原型是数组构造函数本来的原型,即 arrayMethods.__proto__ === Array.prototype。

紧接着:

const arrayProto = Array.prototype

这句使用 arrayProto 变量缓存了 Array.prototype。

再然后:

mutationMethods.forEach(method => {
 arrayMethods[method] = function (...args) {
  const result = arrayProto[method].apply(this, args)
  console.log(`我截获了对数组的${method}操作`)
  return result
 }
})

将 mutationMethods 进行循环,在 arrayMethods 对象上以 mutationMethods 中各元素为 key,即方法名,定义作为拦截器的同名变异方法。

具体:

const result = arrayProto[method].apply(this, args)

执行缓存的 Array.prototype,即 arrayProto 中对应的变异方法,并传入 this 以及 args,也就是将来调用该方法的数组对象,和调用该方法时传入的参数(或参数列表)转化成的参数数组,并将结果给到变量 result。

这里使用了解构赋值的方式将参数(或参数列表)转化成了参数数组,这么做是因为不能确定参数的个数,所以只能使用 apply(不能用 call),并传入参数数组。

之后:

console.log(`我截获了对数组的${method}操作`)

也就是拦截之后要额外执行的操作了。

最后:

return result

将数组原变异方法执行的结果返回,保证原有功能不受影响。

forEach 执行完之后:

const arr = ['kobe', 'jordan']
arr.__proto__ = arrayMethods

声明并初始化 arr,并将 arr 的 __proto__ 指向 arrayMethods,这样便代理了 mutationMethods 中的变异方法。

最终:

arr.push('harden') // '我截获了对数组的push操作'
console.log(JSON.stringify(arr)) // '["kobe","jordan","harden"]'

数组对象手动扩展的功能以及原功能均正常,实现了数组变异方法的拦截。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JavaScript的面向对象(二)
Nov 09 Javascript
javascript Prototype 对象扩展
May 15 Javascript
IE事件对象(The Internet Explorer Event Object)
Jun 27 Javascript
jQuery中多个元素的Hover事件解决方案
Jun 12 Javascript
基于angularjs实现图片放大镜效果
Aug 31 Javascript
JavaScript中Number对象的toFixed() 方法详解
Sep 02 Javascript
JS滚动到指定位置导航栏固定顶部
Jul 03 Javascript
vue.js系列中的vue-fontawesome使用
Feb 10 Javascript
取消Bootstrap的dropdown-menu点击默认关闭事件方法
Aug 10 Javascript
JointJS流程图的绘制方法
Dec 03 Javascript
vue引入微信sdk 实现分享朋友圈获取地理位置功能
Jul 04 Javascript
javascript实现贪吃蛇小游戏
Jul 28 Javascript
Vue项目中最新用到的一些实用小技巧
Nov 06 #Javascript
详解Vue内部怎样处理props选项的多种写法
Nov 06 #Javascript
微信小程序实现选项卡效果
Nov 06 #Javascript
Vue props 单向数据流的实现
Nov 06 #Javascript
给localStorage设置一个过期时间的方法分享
Nov 06 #Javascript
移动端H5页面返回并刷新页面(BFcache)的方法
Nov 06 #Javascript
学习使用ExpressJS 4.0中的新Router的用法
Nov 06 #Javascript
You might like
PHP is_dir() 判断给定文件名是否是一个目录
2010/05/10 PHP
PHP 面向对象程序设计(oop)学习笔记 (四) - 异常处理类Exception
2014/06/12 PHP
Yii框架中使用PHPExcel的方法分析
2019/07/25 PHP
用window.location.href实现刷新另个框架页面
2007/03/07 Javascript
JS array 数组详解
2009/03/22 Javascript
js 调用本地exe的例子(支持IE内核的浏览器)
2012/12/26 Javascript
JavaScript实现x秒后自动跳转到一个页面
2013/01/03 Javascript
JavaScript 实现类的多种方法实例
2013/05/01 Javascript
使用jquery的ajax需要注意的地方dataType的设置
2013/08/12 Javascript
基于JavaScript实现图片点击弹出窗口而不是保存
2016/02/06 Javascript
js重写方法的简单实现
2016/07/10 Javascript
mint-ui在vue中的使用示例
2018/04/05 Javascript
vue实现动态显示与隐藏底部导航的方法分析
2019/02/11 Javascript
ES6中Set和Map数据结构,Map与其它数据结构互相转换操作实例详解
2019/02/28 Javascript
Vue $mount实战之实现消息弹窗组件
2019/04/22 Javascript
浅谈一个webpack构建速度优化误区
2019/06/24 Javascript
JS实现简易计算器
2020/02/14 Javascript
vue 监听窗口变化对页面部分元素重新渲染操作
2020/07/28 Javascript
python基于mysql实现的简单队列以及跨进程锁实例详解
2014/07/07 Python
Python实现的一个自动售饮料程序代码分享
2014/08/25 Python
零基础写python爬虫之神器正则表达式
2014/11/06 Python
详解python 字符串和日期之间转换 StringAndDate
2017/05/04 Python
python实现括号匹配的思路详解
2018/08/23 Python
关于阿里云oss获取sts凭证 app直传 python的实例
2019/08/20 Python
wxpython布局的实现方法
2019/11/01 Python
python数据类型强制转换实例详解
2020/06/22 Python
The North Face意大利官网:服装、背包和鞋子
2020/06/17 全球购物
医学类导师推荐信范文
2013/11/19 职场文书
教师个人剖析材料
2014/02/05 职场文书
大专会计自我鉴定
2014/02/06 职场文书
十一国庆节“向国旗敬礼”主题班会活动方案
2014/09/27 职场文书
办理信用卡工作证明
2014/09/30 职场文书
SpringAop日志找不到方法的处理
2021/06/21 Java/Android
MySQL中的引号和反引号的区别与用法详解
2021/10/24 MySQL
JavaScript最完整的深浅拷贝实现方式详解
2022/02/28 Javascript
Python 绘制多因子柱状图
2022/05/11 Python