浅谈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和jquery批量绑定事件传参数一(新猪猪原创)
Jun 23 Javascript
jquery解析XML字符串和XML文件的方法说明
Feb 21 Javascript
node.js中的fs.statSync方法使用说明
Dec 16 Javascript
Javascript函数式编程简单介绍
Oct 11 Javascript
JavaScript通过使用onerror设置默认图像显示代替alt
Mar 01 Javascript
详解Sea.js中Module.exports和exports的区别
Feb 12 Javascript
自带气泡提示的vue校验插件(vue-verify-pop)
Apr 07 Javascript
解决JS内存泄露之js对象和dom对象互相引用问题
Jun 25 Javascript
Vue入门之animate过渡动画效果
Apr 08 Javascript
vue devtools的安装与使用教程
Aug 08 Javascript
Vue路由history模式解决404问题的几种方法
Sep 29 Javascript
React+TypeScript+webpack4多入口配置详解
Aug 08 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
9条PHP编程小知识及易犯的小错误
2015/01/22 PHP
PHP 计算至少是其他数字两倍的最大数的实现代码
2020/05/26 PHP
js资料toString 方法
2007/03/13 Javascript
JavaScript 学习笔记一些小技巧
2010/03/28 Javascript
JavaScript面向对象(极简主义法minimalist approach)
2012/07/17 Javascript
firefox下jQuery UI Autocomplete 1.8.*中文输入修正方法
2012/09/19 Javascript
js离开或刷新页面检测(且兼容FF,IE,Chrome)
2014/03/05 Javascript
jQuery标签替换函数replaceWith()的使用例子
2014/08/28 Javascript
IE中getElementsByName()对有些元素无效的解决方案
2014/09/28 Javascript
全面解析Bootstrap中Carousel轮播的使用方法
2016/06/13 Javascript
Bootstrap CSS布局之代码
2016/12/17 Javascript
利用JavaScript在网页实现八数码启发式A*算法动画效果
2017/04/16 Javascript
原生JS实现的放大镜特效示例【测试可用】
2018/12/08 Javascript
vue 集成jTopo 处理方法
2019/08/07 Javascript
layui动态加载多表头的实例
2019/09/05 Javascript
Javascript类型判断相关例题及解析
2020/08/26 Javascript
Python中的数据对象持久化存储模块pickle的使用示例
2016/03/03 Python
python 数据的清理行为实例详解
2017/07/12 Python
python读取csv文件并把文件放入一个list中的实例讲解
2018/04/27 Python
对python append 与浅拷贝的实例讲解
2018/05/04 Python
python+opencv像素的加减和加权操作的实现
2019/07/14 Python
django框架创建应用操作示例
2019/09/26 Python
pytorch 实现在预训练模型的 input上增减通道
2020/01/06 Python
详解python中的闭包
2020/09/07 Python
Python+OpenCV图像处理—— 色彩空间转换
2020/10/22 Python
python图片合成的示例
2020/11/09 Python
python 实现数据库中数据添加、查询与更新的示例代码
2020/12/07 Python
《两个铁球同时着地》教学反思
2014/02/13 职场文书
教师一岗双责责任书
2014/04/16 职场文书
工程售后服务方案
2014/06/08 职场文书
铣床操作工岗位职责
2014/06/13 职场文书
敬业奉献模范事迹材料
2014/12/24 职场文书
幼儿园食品安全责任书
2015/05/08 职场文书
《落花生》教学反思
2016/02/16 职场文书
高中美术教学反思
2016/02/17 职场文书
Python 数据可视化工具 Pyecharts 安装及应用
2022/04/20 Python