浅谈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 判断函数类型完美解决方案
Sep 02 Javascript
javascript 表单验证常见正则
Sep 28 Javascript
使用js如何实现全选与全不选
Dec 30 Javascript
浅谈JavaScript的事件
Feb 27 Javascript
jQuery原理系列-css选择器的简单实现
Jun 07 Javascript
基于HTML5+JS实现本地图片裁剪并上传功能
Mar 24 Javascript
ES6新特性之函数的扩展实例详解
Apr 01 Javascript
javascript回调函数的概念理解与用法分析
May 27 Javascript
浅谈ECMAScript6新特性之let、const
Aug 02 Javascript
Vue + Node.js + MongoDB图片上传组件实现图片预览和删除功能详解
Apr 29 Javascript
封装 axios+promise通用请求函数操作
Aug 11 Javascript
Selenium执行JavaScript脚本的方法示例
Dec 31 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的array_multisort()使用方法介绍
2012/05/16 PHP
phpexcel导入excel数据使用方法实例
2013/12/24 PHP
PHP表单提交后引号前自动加反斜杠的原因及三种办法关闭php魔术引号
2015/09/30 PHP
PHP扩展迁移为PHP7扩展兼容性问题记录
2016/02/15 PHP
浅谈php中curl、fsockopen的应用
2016/12/10 PHP
推荐自用 Javascript 缩图函数 (onDOMLoaded)……
2007/10/23 Javascript
js兼容标准的表格变色效果
2008/06/28 Javascript
javascript xml为数据源的下拉框控件
2009/07/07 Javascript
JavaScript 数组循环引起的思考
2010/01/01 Javascript
JS+CSS相对定位实现的下拉菜单
2015/10/06 Javascript
jQuery实现多级联动下拉列表查询框
2016/01/18 Javascript
小白谈谈对JS原型链的理解
2016/05/03 Javascript
Javascript中关于Array.filter()的妙用详解
2016/12/04 Javascript
基于bootstrap的选择框插件icheck
2016/12/23 Javascript
微信小程序遇到修改数据后页面不渲染的问题解决
2017/03/09 Javascript
微信小程序之数据缓存的实例详解
2017/09/29 Javascript
Vuex入门到上手教程
2018/06/20 Javascript
vue 自定义指令自动获取文本框焦点的方法
2018/08/25 Javascript
vue实现微信二次分享以及自定义分享的示例
2019/03/20 Javascript
[01:08]2014DOTA2展望TI 剑指西雅图LGD战队专访
2014/06/30 DOTA
深入理解python中的闭包和装饰器
2016/06/12 Python
Python图像处理之图像的缩放、旋转与翻转实现方法示例
2019/01/04 Python
Pandas之DataFrame对象的列和索引之间的转化
2019/06/25 Python
简单了解python反射机制的一些知识
2019/07/13 Python
Zavvi荷兰:英国大型音像制品和图书游戏零售商
2018/03/22 全球购物
乌克兰网上珠宝商店:GoldSoveren
2020/03/31 全球购物
电子商务专员岗位职责
2013/12/11 职场文书
函授大学生自我鉴定
2014/02/05 职场文书
门球健将观后感
2015/06/16 职场文书
大学生社区义工服务心得体会
2016/01/22 职场文书
导游词之无锡丝业博物馆
2019/11/12 职场文书
python删除csv文件的行列
2021/04/06 Python
goland 设置project gopath的操作
2021/05/06 Golang
Python Pandas pandas.read_sql函数实例用法
2021/06/21 Python
世界十大评分最高的动漫,CLANNAD上榜,第八赚足人们眼泪
2022/03/18 日漫
Python内置数据类型中的集合详解
2022/03/18 Python