浅谈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
Oct 31 Javascript
JS延迟加载(setTimeout) JS最后加载
Jul 15 Javascript
跨浏览器通用、可重用的选项卡tab切换js代码
Sep 20 Javascript
键盘上一张下一张兼容IE/google/firefox等浏览器
Jan 28 Javascript
jQuery给多个不同元素添加class样式的方法
Mar 26 Javascript
javascript通过获取html标签属性class实现多选项卡的方法
Jul 27 Javascript
关于javascript中dataset的问题小结
Nov 16 Javascript
jQuery实现将div中滚动条滚动到指定位置的方法
Aug 10 Javascript
实现点击下箭头变上箭头来回切换的两种方法【推荐】
Dec 14 Javascript
解决VUEX兼容IE上的报错问题
Mar 01 Javascript
javascript中的数据类型检测方法详解
Aug 07 Javascript
vue+elementui通用弹窗的实现(新增+编辑)
Jan 07 Vue.js
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
老照片 - 几十年前的收音机与人
2021/03/02 无线电
PHP开发文件系统实例讲解
2006/10/09 PHP
PHP面向对象分析设计的61条军规小结
2010/07/17 PHP
PHP中实现中文字符进制转换原理分析
2011/12/06 PHP
php 无法加载mysql的module的时候的配置的解决方案引发的思考
2012/01/27 PHP
浅谈PHP表单提交(POST&GET&URL编/解码)
2017/04/03 PHP
Laravel框架文件上传功能实现方法示例
2019/04/16 PHP
清华大学出版的事半功倍系列 javascript全部源代码
2007/05/04 Javascript
js 中{},[]中括号,大括号使用详解
2011/05/12 Javascript
30个精美的jQuery幻灯片效果插件和教程
2011/08/23 Javascript
解决js正则匹配换行问题实现代码
2012/12/10 Javascript
鼠标滚轮改变图片大小的示例代码
2013/11/20 Javascript
js 事件截取enter按键页面提交事件示例代码
2014/03/04 Javascript
基于jQuery实现的幻灯图片切换
2016/12/02 Javascript
bootstrap jquery dataTable 异步ajax刷新表格数据的实现方法
2017/02/10 Javascript
vue.js选中动态绑定的radio的指定项
2017/06/02 Javascript
vue使用Font Awesome的方法步骤
2019/02/26 Javascript
Vue v-text指令简单使用方法示例
2019/09/19 Javascript
Swiper实现导航栏滚动效果
2020/10/16 Javascript
vue项目中企业微信使用js-sdk时config和agentConfig配置方式详解
2020/12/15 Vue.js
python3 实现的人人影视网站自动签到
2016/06/19 Python
python实现校园网自动登录的示例讲解
2018/04/22 Python
python实现扫描日志关键字的示例
2018/04/28 Python
Python3实现监控新型冠状病毒肺炎疫情的示例代码
2020/02/13 Python
python_array[0][0]与array[0,0]的区别详解
2020/02/18 Python
M1芯片安装python3.9.1的实现
2021/02/02 Python
详解使用postMessage解决iframe跨域通信问题
2019/11/01 HTML / CSS
DHC中国官方购物网站:日本通信销售No.1化妆品
2016/08/20 全球购物
乌克兰时尚鞋子和衣服购物网站:Born2be
2018/05/24 全球购物
音乐节策划方案
2014/06/09 职场文书
安全施工责任书
2014/08/25 职场文书
餐厅保洁员岗位职责
2015/04/10 职场文书
检讨书模板大全
2015/05/07 职场文书
详解java如何集成swagger组件
2021/06/21 Java/Android
详解Java线程池是如何重复利用空闲线程的
2021/06/26 Java/Android
python超详细实现完整学生成绩管理系统
2022/03/17 Python