浅谈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里的条件判断
Feb 27 Javascript
getComputedStyle与currentStyle获取样式(style/class)
Mar 19 Javascript
原生js实现shift/ctrl/alt按键的获取
Apr 08 Javascript
一个简单的JS时间控件示例代码(JS时分秒时间控件)
Nov 22 Javascript
javascript实现youku的视频代码自适应宽度
May 25 Javascript
JS实现添加,替换,删除节点元素的方法
Jun 30 Javascript
js实现颜色阶梯渐变效果(Gradient算法)
Mar 21 Javascript
JS使用插件cryptojs进行加密解密数据实例
May 11 Javascript
解决jquery的ajax调取后端数据成功却渲染失败的问题
Aug 08 jQuery
mpvue小程序循环动画开启暂停的实现方法
May 15 Javascript
React 全自动数据表格组件——BodeGrid的实现思路
Jun 12 Javascript
微信小程序 select 下拉框组件功能
Sep 09 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 UTF8编码内的繁简转换类
2009/07/20 PHP
PHP中使用循环实现的金字塔图形
2014/11/08 PHP
php微信支付之APP支付方法
2015/03/04 PHP
PHP正则匹配日期和时间(时间戳转换)的实例代码
2016/12/14 PHP
php生成0~1随机小数的方法(必看)
2017/04/05 PHP
调用js时ie6和ie7,ff的区别
2009/08/19 Javascript
用 Javascript 验证表单(form)中的单选(radio)值
2009/09/08 Javascript
阻止子元素继承父元素事件具体思路及实现
2013/05/02 Javascript
jQuery的cookie插件实现保存用户登陆信息
2014/04/15 Javascript
JavaScript弹出新窗口后向父窗口输出内容的方法
2015/04/06 Javascript
jquery插件bxslider用法实例分析
2015/04/16 Javascript
jQuery中inArray方法注意事项分析
2016/01/25 Javascript
使用openSpeDiv方法实现Ecshop登录弹窗框效果
2017/03/13 Javascript
深入对Vue.js $watch方法的理解
2017/03/20 Javascript
使用Math.max,Math.min获取数组中的最值实例
2017/04/25 Javascript
React Hooks的深入理解与使用
2018/11/12 Javascript
JS/HTML5游戏常用算法之碰撞检测 包围盒检测算法详解【凹多边形的分离轴检测算法】
2018/12/13 Javascript
js逆向解密之网络爬虫
2019/05/30 Javascript
vue在路由中验证token是否存在的简单实现
2019/11/11 Javascript
JavaScript 中的六种循环方法
2021/01/06 Javascript
Python常见加密模块用法分析【MD5,sha,crypt模块】
2017/05/24 Python
python 中if else 语句的作用及示例代码
2018/03/05 Python
Python简单实现查找一个字符串中最长不重复子串的方法
2018/03/26 Python
Python实现统计给定列表中指定数字出现次数的方法
2018/04/11 Python
Python常见数据类型转换操作示例
2019/05/08 Python
详解python解压压缩包的五种方法
2019/07/05 Python
python如何实现单链表的反转
2020/02/10 Python
Python 里最强的地图绘制神器
2021/03/01 Python
美国著名的品牌折扣店:Burlington
2017/06/08 全球购物
新西兰演唱会和体育门票网站:Ticketmaster新西兰
2017/10/07 全球购物
马来西亚最大的在线隐形眼镜商店:MrLens
2019/03/27 全球购物
办公自动化专业大学生职业规划书
2014/03/06 职场文书
保洁公司服务承诺书
2014/05/28 职场文书
2016年教师反腐倡廉心得体会
2016/01/13 职场文书
pytorch 带batch的tensor类型图像显示操作
2021/05/20 Python
HTML常用标签超详细整理
2022/03/19 HTML / CSS