浅谈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 tab 选项卡
Apr 26 Javascript
Textarea与懒惰渲染实现代码
Jan 04 Javascript
解析使用JS 清空File控件的路径值
Jul 08 Javascript
Node.js事件循环(Event Loop)和线程池详解
Jan 28 Javascript
浅谈Jquery核心函数
Jun 18 Javascript
微信公众平台开发教程(五)详解自定义菜单
Dec 02 Javascript
Bootstrap php制作动态分页标签
Dec 23 Javascript
webpack入门+react环境配置
Feb 08 Javascript
Windows下Node.js安装及环境配置方法
Sep 18 Javascript
webpack4的迁移的使用方法
May 25 Javascript
微信小程序仿美团城市选择
Jun 06 Javascript
解决Antd Table组件表头不对齐的问题
Oct 27 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中使用glob函数实现一句话删除某个目录下的所有文件
2014/07/22 PHP
ThinkPHP上使用多说评论插件的方法
2014/10/31 PHP
php对关联数组循环遍历的实现方法
2015/03/13 PHP
php中字符串和整数比较的操作方法
2019/06/06 PHP
JavaScript 事件系统
2010/07/22 Javascript
node.js中的querystring.escape方法使用说明
2014/12/10 Javascript
JavaScript获取文本框内选中文本的方法
2015/02/20 Javascript
js实现表单多按钮提交action的处理方法
2015/10/24 Javascript
jquery validate.js表单验证入门实例(附源码)
2015/11/10 Javascript
浅谈jquery的map()和each()方法
2016/06/12 Javascript
JavaScript实现自动切换图片代码
2016/10/11 Javascript
layui文件上传实现代码
2017/05/20 Javascript
vue实现点击图片放大效果
2017/08/15 Javascript
vue.js $refs和$emit 父子组件交互的方法
2017/12/20 Javascript
pace.js和NProgress.js两个加载进度插件的一点小总结
2018/01/31 Javascript
angular中两种表单的区别(响应式和模板驱动表单)
2018/12/06 Javascript
在antd4.0中Form使用initialValue操作
2020/11/02 Javascript
python实现在目录中查找指定文件的方法
2014/11/11 Python
Python类的用法实例浅析
2015/05/27 Python
Python实现读写sqlite3数据库并将统计数据写入Excel的方法示例
2017/08/07 Python
python实现随机森林random forest的原理及方法
2017/12/21 Python
python处理数据,存进hive表的方法
2018/07/04 Python
python一行sql太长折成多行并且有多个参数的方法
2018/07/19 Python
python简单鼠标自动点击某区域的实例
2019/06/25 Python
python用类实现文章敏感词的过滤方法示例
2019/10/27 Python
wxPython电子表格功能wx.grid实例教程
2019/11/19 Python
怎么快速自学python
2020/06/22 Python
详解Java中一维、二维数组在内存中的结构
2021/02/11 Python
Html5实现文件异步上传功能
2017/05/19 HTML / CSS
中国电子产品外贸网站:MiniIntheBox
2017/02/06 全球购物
在职党员进社区活动总结
2014/07/05 职场文书
岁月神偷观后感
2015/06/11 职场文书
2015中秋节晚会主持词
2015/07/01 职场文书
2016新年年会主持词
2015/07/06 职场文书
用position:sticky完美解决小程序吸顶问题的实现方法
2021/04/24 HTML / CSS
SQL中的三种去重方法小结
2021/11/01 SQL Server