浅谈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的日期选择控件
Oct 27 Javascript
你可能不知道的JavaScript的new Function()方法
Apr 17 Javascript
jQuery 1.9.1源码分析系列(十)事件系统之主动触发事件和模拟冒泡处理
Nov 24 Javascript
理解javascript中的with关键字
Feb 15 Javascript
原生JS实现平滑回到顶部组件
Mar 16 Javascript
简单实现node.js图片上传
Dec 18 Javascript
jQuery实现仿京东防抖动菜单效果示例
Jul 06 jQuery
vue在手机中通过本机IP地址访问webApp的方法
Aug 15 Javascript
vue通过数据过滤实现表格合并
Nov 30 Javascript
微信小程序跨页面数据传递事件响应实现过程解析
Dec 19 Javascript
解决vue-photo-preview 异步图片放大失效的问题
Jul 29 Javascript
react+antd 递归实现树状目录操作
Nov 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为php增加openssl模块的方法
2011/06/14 PHP
phpstorm编辑器乱码问题解决
2014/12/01 PHP
phpinfo()中Loaded Configuration File(none)的解决方法
2017/01/16 PHP
PHP常量及变量区别原理详解
2020/08/14 PHP
javascript 模式设计之工厂模式详细说明
2010/05/10 Javascript
js中的hasOwnProperty和isPrototypeOf方法使用实例
2014/06/06 Javascript
Javascript学习笔记之相等符号与严格相等符号
2014/11/23 Javascript
node.js中的http.response.getHeader方法使用说明
2014/12/14 Javascript
解析javascript中鼠标滚轮事件
2015/05/26 Javascript
初步认识JavaScript函数库jQuery
2015/06/18 Javascript
js代码实现随机颜色的小方块
2015/07/30 Javascript
jQuery中text() val()和html()的区别实例详解
2016/06/28 Javascript
用JS写的一个Ajax库(实例代码)
2016/08/06 Javascript
jQuery中ScrollTo用法示例
2016/09/04 Javascript
vue中各选项及钩子函数执行顺序详解
2018/08/25 Javascript
深入浅析Vue 中 ref 的使用
2019/04/29 Javascript
Node.js 中如何收集和解析命令行参数
2021/01/08 Javascript
[02:50]【扭转乾坤,只此一招】DOTA2全新版本永雾林渊开启新篇章
2020/12/24 DOTA
python控制台显示时钟的示例
2014/02/24 Python
Python中使用Inotify监控文件实例
2015/02/14 Python
django用户登录和注销的实现方法
2018/07/16 Python
一篇文章搞懂Python的类与对象名称空间
2018/12/10 Python
python 自动重连wifi windows的方法
2018/12/18 Python
使用Python自动生成HTML的方法示例
2019/08/06 Python
Python列表切片常用操作实例解析
2019/12/16 Python
Python自动发送和收取邮件的方法
2020/08/12 Python
关于python3.9安装wordcloud出错的问题及解决办法
2020/11/02 Python
CSS实现限制字数功能当对象内文本溢出时显示省略标记
2014/08/20 HTML / CSS
浅谈css3中的前缀
2016/07/20 HTML / CSS
美国知名奢侈美容品牌零售商:Cos Bar
2017/04/21 全球购物
比利时香水网上商店:NOTINO
2018/03/28 全球购物
美国最大的电子宠物训练产品制造商:PetSafe
2018/10/12 全球购物
喜之郎果冻广告词
2014/03/20 职场文书
详解MySQL连接挂死的原因
2021/05/18 MySQL
拒绝盗图!教你怎么用python给图片加水印
2021/06/04 Python
帮你提高开发效率的JavaScript20个技巧
2021/06/18 Javascript