浅谈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 相关文章推荐
执行iframe中的javascript方法
Oct 07 Javascript
非常棒的10款jQuery 幻灯片插件
Jun 14 Javascript
javascript操作css属性
Dec 30 Javascript
javascript实现简单的html5视频播放器
May 06 Javascript
Angular.js组件之input mask对input输入进行格式化详解
Jul 10 Javascript
解决iview打包时UglifyJs报错的问题
Mar 07 Javascript
微信小程序http连接访问解决方案的示例
Nov 05 Javascript
vue计算属性computed、事件、监听器watch的使用讲解
Jan 21 Javascript
深入理解Vue keep-alive及实践总结
Aug 21 Javascript
vuex根据不同的用户权限展示不同的路由列表功能
Sep 20 Javascript
JS实现动态倒计时功能(天数、时、分、秒)
Dec 12 Javascript
JavaScript实现弹出窗口效果
Dec 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 cout<<的一点看法
2010/01/24 PHP
php计算两个坐标(经度,纬度)之间距离的方法
2015/04/17 PHP
PHP常见错误提示含义解释(实用!值得收藏)
2016/04/25 PHP
event对象的方法 兼容多浏览器
2009/06/27 Javascript
JavaScript对象之间的转换 jQuery对象和原声DOM
2011/03/07 Javascript
JS按位非(~)运算符与~~运算符的理解分析
2011/07/31 Javascript
jQuery瀑布流插件Wookmark使用实例
2014/04/02 Javascript
jQuery+ajax实现无刷新级联菜单示例
2015/05/21 Javascript
require.js配合插件text.js实现最简单的单页应用程序
2016/07/12 Javascript
BootStrap 附加导航组件
2016/07/22 Javascript
Javascript typeof与instanceof的区别
2016/10/18 Javascript
正则中的回溯定义与用法分析【JS与java实现】
2016/12/27 Javascript
完美实现js焦点轮播效果(二)(图片可滚动)
2017/03/07 Javascript
微信小程序 MD5的方法详解及实例代码
2017/03/10 Javascript
js对象数组和对象的使用实例详解
2019/08/27 Javascript
微信小程序实用代码段(收藏版)
2019/12/17 Javascript
antd Form组件方法getFieldsValue获取自定义组件的值操作
2020/10/29 Javascript
JavaScript中展开运算符及应用的实例代码
2021/01/14 Javascript
python实现聚类算法原理
2018/02/12 Python
python 列表降维的实例讲解
2018/06/28 Python
Python连接Mssql基础教程之Python库pymssql
2018/09/16 Python
PyTorch搭建一维线性回归模型(二)
2019/05/22 Python
Python 转换文本编码实现解析
2019/08/27 Python
Python统计学一数据的概括性度量详解
2020/03/03 Python
python 按钮点击关闭窗口的实现
2020/03/04 Python
使用python处理题库表格并转化为word形式的实现
2020/04/14 Python
python如何输出反斜杠
2020/06/18 Python
香港演唱会订票网站:StubHub香港
2019/10/10 全球购物
英文版餐饮运营管理求职信
2013/11/06 职场文书
董事长岗位职责
2013/11/30 职场文书
前台文员岗位职责
2013/12/28 职场文书
教学实习自我评价
2014/01/28 职场文书
销售主管岗位职责
2014/02/08 职场文书
机械制造毕业生求职信
2014/03/03 职场文书
幼儿园园长新年寄语
2015/08/17 职场文书
Vue实现动态查询规则生成组件
2021/05/27 Vue.js