浅谈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 相关文章推荐
js 中 document.createEvent的用法
Aug 29 Javascript
JavaScript学习点滴 call、apply的区别
Oct 22 Javascript
js取消单选按钮选中示例代码
Nov 14 Javascript
jQuery中的read和JavaScript中的onload函数的区别
Aug 27 Javascript
jQuery实现感应鼠标动画效果自动伸长的输入框实例
Feb 24 Javascript
jQuery实现页面顶部显示的进度条效果完整实例
Dec 09 Javascript
js中遍历对象的属性和值的方法
Jul 27 Javascript
vscode下vue项目中eslint的使用方法
Jan 13 Javascript
vue使用自定义指令实现拖拽
Jan 29 Javascript
序列化模块json代码实例详解
Mar 03 Javascript
Node.js API详解之 string_decoder用法实例分析
Apr 29 Javascript
JavaScript实现手机号码 3-4-4格式并控制新增和删除时光标的位置
Jun 02 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获取当前网址url并替换参数或网址的方法
2010/06/06 PHP
php实现的获取网站备案信息查询代码(360)
2013/09/23 PHP
PHP 闭包详解及实例代码
2016/09/28 PHP
详解PHP安装mysql.so扩展的方法
2016/12/31 PHP
php输出含有“#”字符串的方法
2017/01/18 PHP
PHP实现网页内容html标签补全和过滤的方法小结【2种方法】
2017/04/27 PHP
PHP receiveMail实现收邮件功能
2018/04/25 PHP
PHP Laravel中的Trait使用方法
2019/01/20 PHP
Yii框架 session 数据库存储操作方法示例
2019/11/18 PHP
php+mysql+ajax 局部刷新点赞/取消点赞功能(每个账号只点赞一次)
2020/07/24 PHP
Jquery 快速构建可拖曳的购物车DragDrop
2009/11/30 Javascript
HTML中的setCapture和releaseCapture使用介绍
2012/03/21 Javascript
node.js中的http.response.getHeader方法使用说明
2014/12/14 Javascript
jQuery仿天猫实现超炫的加入购物车
2015/05/04 Javascript
使用AngularJS来实现HTML页面嵌套的方法
2015/06/17 Javascript
vue中用动态组件实现选项卡切换效果
2017/03/25 Javascript
jQuery实现验证表单密码一致性及正则表达式验证邮箱、手机号的方法
2017/12/05 jQuery
nodejs中用npm初始化来创建package.json的实例讲解
2018/10/10 NodeJs
JS中appendChild追加子节点无效的解决方法
2018/10/14 Javascript
JS/HTML5游戏常用算法之碰撞检测 包围盒检测算法详解【矩形情况】
2018/12/13 Javascript
vue通过数据过滤实现表格合并
2020/11/30 Javascript
JS实现放大镜效果
2020/09/21 Javascript
调试Python程序代码的几种方法总结
2015/04/28 Python
用python与文件进行交互的方法
2018/03/01 Python
python使用参数对嵌套字典进行取值的方法
2019/04/26 Python
python增加图像对比度的方法
2019/07/12 Python
python自动化实现登录获取图片验证码功能
2019/11/20 Python
python opencv图片编码为h264文件的实例
2019/12/12 Python
Python实现JS解密并爬取某音漫客网站
2020/10/23 Python
HTML5+CSS3应用详解
2014/02/24 HTML / CSS
印度低票价航空公司:GoAir
2017/10/11 全球购物
俄语地区最大的中国商品在线购物网站之一:Umka Mall
2019/11/03 全球购物
亿企通软件测试面试题
2012/04/10 面试题
新农村建设指导员工作总结
2015/08/13 职场文书
致创业您:正能量激励人心句子(48条)
2019/08/15 职场文书
Python机器学习之决策树和随机森林
2021/07/15 Javascript