浅谈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刷新当前页面的几种方法总结
Dec 24 Javascript
ExtJS中设置下拉列表框不可编辑的方法
May 07 Javascript
利用原生JavaScript获取元素样式只是获取而已
Oct 08 Javascript
使用JQ来编写最基本的淡入淡出效果附演示动画
Oct 31 Javascript
Node.js如何自动审核团队的代码
Jul 20 Javascript
JS正则验证多个邮箱完整实例【邮箱用分号隔开】
Apr 19 Javascript
详解angularjs的数组传参方式的简单实现
Jul 28 Javascript
微信小程序基于slider组件动态修改标签透明度的方法示例
Dec 04 Javascript
Vue表单demo v-model双向绑定问题
Jun 29 Javascript
Vuejs监听vuex中值的变化的方法示例
Dec 02 Javascript
vue vantUI实现文件(图片、文档、视频、音频)上传(多文件)
Oct 15 Javascript
微信小程序实现禁止分享代码实例
Oct 19 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
全国FM电台频率大全 - 16 河南省
2020/03/11 无线电
php cli模式学习(PHP命令行模式)
2013/06/03 PHP
PHP判断是否有Get参数的方法
2014/05/05 PHP
PHP 访问数据库配置通用方法(json)
2018/05/20 PHP
jquery ready函数源代码研究
2009/12/06 Javascript
js innerHTML 改变div内容的方法
2013/08/03 Javascript
用js来获取上传的文件名纯粹是为了美化而用
2013/10/23 Javascript
Nodejs全栈框架StrongLoop推荐
2014/11/09 NodeJs
详解Vue.js动态绑定class
2016/12/20 Javascript
jQuery EasyUI 页面加载等待及页面等待层
2017/02/06 Javascript
Vue.js展示AJAX数据简单示例讲解
2017/03/29 Javascript
微信小程序使用toast消息对话框提示用户忘记输入用户名或密码功能【附源码下载】
2017/12/09 Javascript
Hexo已经看腻了,来手把手教你使用VuePress搭建个人博客
2018/04/26 Javascript
小程序图片剪裁加旋转的示例代码
2018/07/10 Javascript
nodejs 十六进制字符串型数据与btye型数据相互转换
2018/07/30 NodeJs
JS中数据结构与算法---排序算法(Sort Algorithm)实例详解
2019/06/17 Javascript
[50:11]2018DOTA2亚洲邀请赛 4.7总决赛 LGD vs Mineski 第三场
2018/04/09 DOTA
[01:03:36]DOTA2-DPC中国联赛 正赛 VG vs Magma BO3 第二场 1月26日
2021/03/11 DOTA
使用setup.py安装python包和卸载python包的方法
2013/11/27 Python
python遍历类中所有成员的方法
2015/03/18 Python
python爬虫使用cookie登录详解
2017/12/27 Python
在IPython中执行Python程序文件的示例
2018/11/01 Python
python 移动图片到另外一个文件夹的实例
2019/01/10 Python
python开发之anaconda以及win7下安装gensim的方法
2019/07/05 Python
在线服装零售商:SheIn
2016/07/22 全球购物
Boda Skins皮衣官网:奢侈皮夹克,全球配送
2016/12/15 全球购物
中邮全球便购:中国邮政速递物流
2017/03/04 全球购物
德国自然时尚和有机产品购物网站:Waschbär
2019/05/29 全球购物
西班牙最好的在线购买葡萄酒的商店:Vinoseleccion
2019/10/30 全球购物
通信工程毕业生求职信
2013/11/16 职场文书
实习生的自我鉴定范文欣赏
2013/11/20 职场文书
失业者真诚求职信范文
2013/12/25 职场文书
学会用Python实现滑雪小游戏,再也不用去北海道啦
2021/05/20 Python
通过Qt连接OpenGauss数据库的详细教程
2021/06/23 PostgreSQL
纯 CSS 自定义多行省略的问题(从原理到实现)
2021/11/11 HTML / CSS
Java版 简易五子棋小游戏
2022/05/04 Java/Android