浅谈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 关于event.target使用的几点说明介绍
Apr 26 Javascript
页面元素绑定jquery toggle后元素隐藏的解决方法
Mar 27 Javascript
超链接的禁用属性Disabled使用示例
Jul 31 Javascript
为什么Node.js会这么火呢?Node.js流行的原因
Dec 01 Javascript
详解JavaScript对W3C DOM模版的支持情况
Jun 16 Javascript
JavaScript中style.left与offsetLeft的使用及区别详解
Jun 08 Javascript
JavaScript模板引擎Template.js使用详解
Dec 15 Javascript
jQuery Ajax 实现在html页面实时显示用户登录状态
Dec 30 Javascript
JavaScript获取select中text值的方法
Feb 13 Javascript
vue的基本用法与常见指令
Aug 15 Javascript
监听element-ui table滚动事件的方法
Mar 26 Javascript
JavaScript类的继承多种实现方法
May 30 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分页效率终结版(推荐)
2013/07/01 PHP
深入理解Yii2.0乐观锁与悲观锁的原理与使用
2017/07/26 PHP
php对象工厂类完整示例
2018/08/09 PHP
tp5框架前台无限极导航菜单类实现方法分析
2020/03/29 PHP
解决 firefox 不支持 document.all的方法
2007/03/12 Javascript
javascript 密码强弱度检测万能插件
2009/02/25 Javascript
JS在IE和FireFox之间常用函数的区别小结
2010/03/12 Javascript
JavaScript调用堆栈及setTimeout使用方法深入剖析
2013/02/16 Javascript
基于jquery插件制作左右按钮与标题文字图片切换效果
2013/11/07 Javascript
js实现鼠标移到链接文字弹出一个提示层的方法
2015/05/11 Javascript
JS实现带鼠标效果的头像及文章列表代码
2015/09/27 Javascript
javascript随机抽取0-100之间不重复的10个数
2016/02/25 Javascript
jquery $.trim()去除字符串空格的实现方法【附图例】
2016/03/30 Javascript
基于node下的http小爬虫的示例代码
2018/01/11 Javascript
详解ES6 Promise对象then方法链式调用
2018/10/20 Javascript
vue实现百度下拉列表交互操作示例
2019/03/12 Javascript
vue router导航守卫(router.beforeEach())的使用详解
2019/04/19 Javascript
[05:09]第二届DOTA2亚洲邀请赛决赛日比赛集锦:iG 3:0 OG夺冠
2017/04/05 DOTA
使用python编写android截屏脚本双击运行即可
2014/07/21 Python
用Python中的__slots__缓存资源以节省内存开销的方法
2015/04/02 Python
Mac中Python 3环境下安装scrapy的方法教程
2017/10/26 Python
PyCharm搭建Spark开发环境实现第一个pyspark程序
2019/06/13 Python
详解PANDAS 数据合并与重塑(join/merge篇)
2019/07/09 Python
python 随机森林算法及其优化详解
2019/07/11 Python
python tkinter组件摆放方式详解
2019/09/16 Python
python 爬虫百度地图的信息界面的实现方法
2019/10/27 Python
部队万能检讨书
2014/02/20 职场文书
《飞向蓝天的恐龙》教学反思
2014/04/09 职场文书
微笑面对生活演讲稿
2014/05/13 职场文书
激励员工的口号
2014/06/16 职场文书
教师竞聘上岗演讲稿
2014/09/03 职场文书
2014年保育员个人工作总结
2014/12/02 职场文书
建筑质检员岗位职责
2015/04/08 职场文书
初中思品教学反思
2016/02/20 职场文书
七年级之开学家长寄语35句
2019/09/05 职场文书
德生2P3收音机开箱评测
2022/04/30 无线电