浅谈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 相关文章推荐
Extjs中使用extend(js继承) 的代码
Mar 15 Javascript
A标签中通过href和onclick传递的this对象实现思路
Apr 19 Javascript
放弃用你的InnerHTML来输出HTML吧 jQuery Tmpl不详细讲解
Apr 20 Javascript
使用js对select动态添加和删除OPTION示例代码
Aug 12 Javascript
Js与下拉列表处理问题解决
Feb 13 Javascript
javascript:void(0)是什么意思及href=#与href=javascriptvoid(0)的区别
Nov 13 Javascript
实例解析jQuery中proxy()函数的用法
May 24 Javascript
Node.js服务器开启Gzip压缩教程
Aug 11 Javascript
使用classList来实现两个按钮样式的切换方法
Jan 24 Javascript
Vue实现一个图片懒加载插件
Mar 11 Javascript
30分钟精通React今年最劲爆的新特性——React Hooks
Mar 11 Javascript
如何使用jQuery操作Cookies方法解析
Sep 08 jQuery
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列出MySQL中所有数据库的方法
2015/03/12 PHP
百度地图API使用方法详解
2015/08/25 PHP
PHP正则表达式过滤html标签属性(DEMO)
2016/05/04 PHP
图文详解PHP环境搭建教程
2016/07/16 PHP
yii2高级应用之自定义组件实现全局使用图片上传功能的方法
2016/10/08 PHP
解决php-fpm.service not found问题的办法
2017/06/06 PHP
PDO::query讲解
2019/01/29 PHP
phpstorm最新激活码分享亲测phpstorm2020.2.3版可用
2020/11/22 PHP
extjs表格文本启用选择复制功能具体实现
2013/10/11 Javascript
jQuery插件ajaxFileUpload实现异步上传文件效果
2015/04/14 Javascript
详解JavaScript中的forEach()方法的使用
2015/06/08 Javascript
JS实现从连接中获取youtube的key实例
2015/07/02 Javascript
实例详解JSON数据格式及json格式数据域字符串相互转换
2016/01/07 Javascript
javascript函数命名的三种方式及区别介绍
2016/03/22 Javascript
JavaScript中输出信息的方法(信息确认框-提示输入框-文档流输出)
2016/06/12 Javascript
JavaScript基于原型链的继承
2016/06/22 Javascript
JS 终止执行的实现方法
2016/11/24 Javascript
JavaScript实现离开页面前提示功能【附jQuery实现方法】
2017/09/26 jQuery
JS基于开关思想实现的数组去重功能【案例】
2019/02/18 Javascript
浅谈ECMAScript 中的Array类型
2019/06/10 Javascript
BootstrapValidator验证用户名已存在(ajax)
2019/11/08 Javascript
webpack.DefinePlugin与cross-env区别详解
2020/02/23 Javascript
Element实现表格嵌套、多个表格共用一个表头的方法
2020/05/09 Javascript
Python 基础教程之包和类的用法
2017/02/23 Python
HTML中使用python屏蔽一些基本功能的方法
2017/07/07 Python
python开发游戏的前期准备
2019/05/05 Python
利用Python的turtle库绘制玫瑰教程
2019/11/23 Python
美国领先的家居装饰和礼品商店:Kirkland’s
2017/01/30 全球购物
党员年终民主评议的自我评价
2013/11/05 职场文书
烹调加工管理制度
2014/02/04 职场文书
《猫》教学反思
2014/02/26 职场文书
网络管理员岗位职责
2014/03/17 职场文书
南京青奥会口号
2014/06/12 职场文书
小学2016年“我们的节日·重阳节”活动总结
2016/04/01 职场文书
一篇文章弄清楚Ajax请求的五个步骤
2022/03/17 Javascript
TV动画《八十龟酱观察日记》第四季宣传PV公布
2022/04/06 日漫