浅谈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 相关文章推荐
js中的escape及unescape函数的php实现代码
Sep 04 Javascript
JavaScript 验证浏览器是否支持javascript的方法小结
May 17 Javascript
JS控件的生命周期介绍
Oct 22 Javascript
jQuery选择器之基本选择器与层次选择器
Mar 03 Javascript
使用jQuery在对象中缓存选择器的简单方法
Jun 30 Javascript
Bootstrap Chart组件使用教程
Apr 28 Javascript
微信小程序商品到详情的实现
Jun 27 Javascript
基于JSON数据格式详解
Aug 31 Javascript
简述JS浏览器的三种弹窗
Jul 15 Javascript
Vue.js上传图片到阿里云OSS存储的方法示例
Dec 13 Javascript
React优化子组件render的使用
May 12 Javascript
vuex页面刷新导致数据丢失的解决方案
Dec 10 Vue.js
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
重置版游戏视频
2020/04/09 魔兽争霸
Ha0k 0.3 PHP 网页木马修改版
2009/10/11 PHP
PHP 巧用数组降低程序的时间复杂度
2010/01/01 PHP
php的一些小问题
2010/07/03 PHP
php并发对MYSQL造成压力的解决方法
2013/02/21 PHP
PHP表单提交后引号前自动加反斜杠的原因及三种办法关闭php魔术引号
2015/09/30 PHP
php用户名的密码加密更安全的方法
2019/06/21 PHP
Chrome中JSON.parse的特殊实现
2011/01/12 Javascript
非常有用的40款jQuery 插件推荐(系列二)
2011/12/25 Javascript
js将iframe中控件的值传到主页面控件中的实现方法
2013/03/11 Javascript
js工具方法弹出蒙版
2013/05/08 Javascript
js强制把网址设为默认首页
2015/09/29 Javascript
原生js页面滚动延迟加载图片
2015/12/20 Javascript
浅谈$('div a') 与$('div>a')的区别
2016/07/18 Javascript
Javascript中字符串replace方法的第二个参数探究
2016/12/05 Javascript
详解基于vue-cli3快速发布一个fullpage组件
2019/03/08 Javascript
微信小程序rich-text富文本用法实例分析
2019/05/20 Javascript
vue+vant-UI框架实现购物车的复选框全选和反选功能
2019/11/05 Javascript
Vue实现兄弟组件间的联动效果
2020/01/21 Javascript
Python采集腾讯新闻实例
2014/07/10 Python
Python UnicodeEncodeError: 'gbk' codec can't encode character 解决方法
2015/04/24 Python
Python3实现将文件树中所有文件和子目录归档到tar压缩文件的方法
2015/05/22 Python
Phantomjs抓取渲染JS后的网页(Python代码)
2016/05/13 Python
Python实现SMTP发送邮件详细教程
2021/03/02 Python
利用Python批量提取Win10锁屏壁纸实战教程
2018/03/27 Python
python爬虫爬取某网站视频的示例代码
2021/02/20 Python
css3给背景图片加颜色遮罩的方法
2019/11/05 HTML / CSS
HTML5的结构和语义(5):内嵌媒体
2008/10/17 HTML / CSS
Html5在手机端调用相机的方法实现
2020/05/13 HTML / CSS
医学护理毕业生自荐信
2013/11/07 职场文书
投标承诺书范本
2014/03/27 职场文书
如何做好员工培训计划?
2019/07/09 职场文书
100句拼搏进取的名言警句,值得一读!
2019/10/07 职场文书
css3 filter属性的使用简介
2021/03/31 HTML / CSS
2022年四月新番
2022/03/15 日漫
Python实现归一化算法详情
2022/03/18 Python