浅谈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 相关文章推荐
jQuery代码优化 选择符篇
Nov 01 Javascript
JavaScript 参数中的数组展开 [译]
Sep 21 Javascript
购物车选中得到价格实现示例
Jan 26 Javascript
js图片延迟技术一般的思路与示例
Mar 20 Javascript
javascript移出节点removeChild()使用介绍
Apr 03 Javascript
javascript类型系统 Array对象学习笔记
Jan 09 Javascript
微信小程序 swiper组件详解及实例代码
Oct 25 Javascript
JavaScript中创建对象的7种模式详解
Feb 21 Javascript
Bootstrap 中data-[*] 属性的整理
Mar 13 Javascript
教你如何用node连接redis的示例代码
Jul 12 Javascript
中级前端工程师必须要掌握的27个JavaScript 技巧(干货总结)
Sep 23 Javascript
深入理解基于vue-cli的webpack打包优化实践及探索
Oct 14 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加密解密的代码
2007/07/16 PHP
destoon复制新模块的方法
2014/06/21 PHP
PHP使用内置dir类实现目录遍历删除
2015/03/31 PHP
PHP基于IMAP收取邮件的方法示例
2017/08/07 PHP
测试你的JS的掌握程度的代码
2009/12/09 Javascript
javascript 不间断的图片滚动并可点击
2010/01/15 Javascript
基于jquery的direction图片渐变动画效果
2010/05/24 Javascript
DD_belatedPNG,IE6下PNG透明解决方案(国外)
2010/12/06 Javascript
Javascript创建自定义对象 创建Object实例添加属性和方法
2012/06/04 Javascript
javascript实现全角转半角的方法
2016/01/23 Javascript
移动端js触摸事件详解
2016/09/18 Javascript
JavaScript实现的CRC32函数示例
2016/11/23 Javascript
两种简单的跨域方法(jsonp、php)
2017/01/02 Javascript
浅谈Vue.js 1.x 和 2.x 实例的生命周期
2017/07/25 Javascript
javascript实现最长公共子序列实例代码
2018/02/05 Javascript
Vue Element 分组+多选+可搜索Select选择器实现示例
2018/07/23 Javascript
iview通过Dropdown(下拉菜单)实现的右键菜单
2018/10/26 Javascript
微信小程序利用button控制条件标签的变量问题
2020/03/15 Javascript
uniapp实现可滑动选项卡
2020/10/21 Javascript
[01:03:47]VP vs NewBee Supermajor 胜者组 BO3 第一场 6.5
2018/06/06 DOTA
使用Python编写一个简单的tic-tac-toe游戏的教程
2015/04/16 Python
Perl中著名的Schwartzian转换问题解决实现
2015/06/02 Python
Python开发如何在ubuntu 15.10 上配置vim
2016/01/25 Python
tensorflow识别自己手写数字
2018/03/14 Python
Python json转字典字符方法实例解析
2020/04/13 Python
python利用递归方法实现求集合的幂集
2020/09/07 Python
探索HTML5本地存储功能运用技巧
2016/03/02 HTML / CSS
阿迪达斯意大利在线商店:adidas意大利
2016/09/19 全球购物
来自圣地亚哥的实惠太阳镜:Knockaround
2018/08/27 全球购物
Everything But Water官网:美国泳装品牌
2019/03/17 全球购物
安全教育心得体会
2013/12/29 职场文书
捐助倡议书范文
2014/04/15 职场文书
企业文化理念标语
2014/06/10 职场文书
忠诚教育心得体会
2014/09/03 职场文书
Redis实战高并发之扣减库存项目
2022/04/14 Redis
Oracle 11g数据库使用expdp每周进行数据备份并上传到备份服务器
2022/06/28 Oracle