浅谈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 相关文章推荐
Web开发者必备的12款超赞jQuery插件
Dec 03 Javascript
Json2Template.js 基于jquery的插件 绑定JavaScript对象到Html模板中
Oct 29 Javascript
FireFox下XML对象转化成字符串的解决方法
Dec 09 Javascript
jquery 获取自定义属性(attr和prop)的实现代码
Jun 27 Javascript
js清空form表单中的内容示例
May 20 Javascript
JSON.parse()和JSON.stringify()使用介绍
Jun 20 Javascript
jQuery层动画定位滑动效果的方法
Apr 30 Javascript
javascript insertAfter()定义与用法示例
Jul 25 Javascript
Web前端框架bootstrap实战【第一次接触使用】
Dec 28 Javascript
JavaScript运动框架 链式运动到完美运动(五)
May 18 Javascript
简单谈谈CommonsChunkPlugin抽取公共模块
Dec 31 Javascript
BootStrap模态框闪退问题实例代码详解
Dec 10 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实现添加购物车功能
2017/03/06 PHP
PHPCrawl爬虫库实现抓取酷狗歌单的方法示例
2017/12/21 PHP
取得传值的函数
2006/10/27 Javascript
javascript dom 操作详解 js加强
2009/07/13 Javascript
JavaScript 加号(+)运算符号
2009/12/06 Javascript
JavaScript学习笔记(十七)js 优化
2010/02/04 Javascript
基于javascript 闭包基础分享
2013/07/10 Javascript
提取字符串中年月日的函数代码
2013/11/05 Javascript
用unescape反编码得出汉字示例
2014/04/24 Javascript
谈谈对JavaScript原生拖放的深入理解
2016/09/20 Javascript
JSON 必知必会 观后记
2016/10/27 Javascript
从零开始学习Node.js系列教程四:多页面实现的数学运算示例
2017/04/13 Javascript
实例详解BootStrap的动态模态框及静态模态框
2018/08/13 Javascript
Windows下Node爬虫神器Puppeteer安装记
2019/01/09 Javascript
vue css 引入asstes中的图片无法显示的四种解决方法
2020/03/16 Javascript
python逐行读取文件内容的三种方法
2014/01/20 Python
Python批量转换文件编码格式
2015/05/17 Python
python3实现公众号每日定时发送日报和图片
2018/02/24 Python
Python登录注册验证功能实现
2018/06/18 Python
Python闭包思想与用法浅析
2018/12/27 Python
在PyCharm的 Terminal(终端)切换Python版本的方法
2019/08/02 Python
python计算无向图节点度的实例代码
2019/11/22 Python
python列表生成器迭代器实例解析
2019/12/19 Python
HTML5 3D衣服摇摆动画特效
2016/03/17 HTML / CSS
巴西男士个人护理产品商店:SHOP4MEN
2017/08/07 全球购物
Servlet如何得到服务器的信息
2015/12/22 面试题
高级人员简历的自我评价分享
2013/11/03 职场文书
《假如》教学反思
2014/04/17 职场文书
初三学生评语大全
2014/04/24 职场文书
模具专业求职信
2014/06/26 职场文书
民主生活会批评与自我批评总结
2014/10/17 职场文书
领导个人查摆剖析材料
2014/10/29 职场文书
网络营销计划书
2015/01/17 职场文书
Python多个MP4合成视频的实现方法
2021/07/16 Python
html form表单基础入门案例讲解
2021/07/21 HTML / CSS
Python实现照片卡通化
2021/12/06 Python