浅谈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 相关文章推荐
在修改准备发的批量美化select+可修改select时,在非IE下发现了几个问题
Jan 09 Javascript
parentElement,srcElement的使用小结
Jan 13 Javascript
js中小数转换整数的方法
Jan 26 Javascript
js中运算符&& 和 || 的使用记录
Aug 21 Javascript
Javascript闭包(Closure)详解
May 05 Javascript
jQuery实现订单提交页发送短信功能前端处理方法
Jul 04 Javascript
全面了解构造函数继承关键apply call
Jul 26 Javascript
BootStrap日期控件在模态框中选择时间下拉菜单无效的原因及解决办法(火狐下不能点击)
Aug 18 Javascript
React props和state属性的具体使用方法
Apr 12 Javascript
vue.js实现会动的简历(包含底部导航功能,编辑功能)
Apr 08 Javascript
详解关于html,css,js三者的加载顺序问题
Apr 10 Javascript
小程序实现可拖动的悬浮按钮
Sep 07 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+xml实现在线英文词典之添加词条的方法
2015/01/23 PHP
php模拟post提交数据的方法
2015/02/12 PHP
PHP准确取得服务器IP地址的方法
2015/06/02 PHP
Laravel4中的Validator验证扩展用法详解
2016/07/26 PHP
js常用数组操作方法简明总结
2014/06/20 Javascript
jQuery中extend()和fn.extend()方法详解
2015/06/03 Javascript
node.js微信公众平台开发教程
2016/03/04 Javascript
非常实用的js验证框架实现源码 附原理方法
2016/06/08 Javascript
jQuery实现为LI列表前3行设置样式的方法【2种方法】
2016/09/04 Javascript
Nodejs 发送Post请求功能(发短信验证码例子)
2017/02/09 NodeJs
selenium 与 chrome 进行qq登录并发邮件操作实例详解
2017/04/06 Javascript
JavaScript基础心法 深浅拷贝(浅拷贝和深拷贝)
2018/03/05 Javascript
vue 右键菜单插件 简单、可扩展、样式自定义的右键菜单
2018/11/29 Javascript
ES6知识点整理之对象解构赋值应用示例
2019/04/17 Javascript
基于Fixed定位的框选功能的实现代码
2019/05/13 Javascript
JavaScript 作用域实例分析
2019/10/02 Javascript
vue keep-alive列表页缓存 详情页返回上一页不刷新,定位到之前位置
2019/11/26 Javascript
vue实现全屏滚动效果(非fullpage.js)
2020/03/07 Javascript
Vue中watch、computed、updated三者的区别及用法
2020/07/27 Javascript
浅析Python中yield关键词的作用与用法
2016/11/29 Python
python 类对象和实例对象动态添加方法(分享)
2017/12/31 Python
Tensorflow实现卷积神经网络用于人脸关键点识别
2018/03/05 Python
转换科学计数法的数值字符串为decimal类型的方法
2018/07/16 Python
在Python中COM口的调用方法
2019/07/03 Python
Python绘制全球疫情变化地图的实例代码
2020/04/20 Python
python代码中怎么换行
2020/06/17 Python
Python装饰器如何实现修复过程解析
2020/09/05 Python
英国最大的在线奢侈手表零售商:Jura Watches
2018/01/29 全球购物
Microsoft Advertising美国:微软搜索广告
2019/05/01 全球购物
如何查看在weblogic中已经发布的EJB
2012/06/01 面试题
新闻专业个人求职信
2013/12/19 职场文书
小学毕业感言300字
2014/02/19 职场文书
单位工程竣工验收方案
2014/03/16 职场文书
护士优质服务演讲稿
2014/08/26 职场文书
2014年领导班子专项整治整改方案
2014/09/28 职场文书
校园之声广播稿
2015/08/18 职场文书