vue数据响应式原理重写函数实现数组响应式监听

 更新时间:2023年05月16日 11:12:27   作者:-耿瑞-  
Vue的通过数据劫持的方式实现数据的双向绑定,即使用Object.defineProperty()来实现对属性的劫持,但是Object.defineProperty()中的setter是无法直接实现数组中值的改变的劫持行为的,需要的朋友可以参考下

output.js代码:

import { observe } from "./dataResp"
const output = () => {
    var obj = {
        data: {
            data: {
                map: {
                    dom: {
                        isgin: true
                    }
                },
                arg: 13
            },
            name: "小猫猫"
        },
        bool: [1,2,3,4]
    };
    observe(obj);
    obj.bool.push(7);
    document.getElementById("text").innerHTML = obj.data.name;
}
export default output

运行结果如下

在这里插入图片描述

很明显 我们数组并捕获不到 push方法 除了 push 很多数组方法都捕获不到

首先 我们来看几个方法 分别是

在这里插入图片描述

这几个方法执行 说明 当前数组被改写了内容

那么 我们可以去改写这七个方法 我们在案例 src目录下创建 Arrays.js 然后 大家先要知道 这些方法被定义在哪里? Array.prototype Array是数组类型的一个类对象 这些方法就定义在Array的原型链上 所以 大家才能通过 数组.这些方法 去调用他们 而我们要做的就是 重写这些方法 要做的就是 调用原来的方法 然后 在后面再去做自己需要做的响应式的事情

我们先在src下创建一个def.js 然后将之前写在dataResp.js中的def放进def.js来

export const def = function(obj,key,value,enumerable) {
    Object.defineProperty(obj,key,{
        value,
        enumerable,
        //true  设为可写
        writable: true,
        //true  设为可被删除
        configurable: true
    });
}

然后 将dataResp.js中的def方法干掉 然后 dataResp.js引入一下def.js的 def方法

import {<!--{C}%3C!%2D%2D%20%2D%2D%3E--> def } from './def.js';

这个是我之前没想清楚 抱歉

然后 我们在Arrays.js中编写代码如下

import { def } from './def.js';
const arrayPrototype = Array.prototype;
export const arrayMethods = Object.create(arrayPrototype);
const redefineArrayMethod = [
    'push',
    'pop',
    'shift',
    'unshift',
    'splice',
    'sort',
    'reverse'
]
redefineArrayMethod.forEach(item =>{
    const backupFunction = arrayPrototype[item];
    def(arrayMethods,item,function(){
        backupFunction.apply(this, arguments);
        console.log('数组执行了',item,'操作,值被修改为',this);
    },false);
})

这里 我们先定义了redefineArrayMethod变量 他的值是一个数组 对应下面每一个字符串下标 都是这些改变数组结构的函数关键字

然后定义 arrayPrototype 存一下Array的 原型链 prototype 因为 这些函数就在上面

然后 创建arrayMethods 记录创建数组 并将arrayPrototype

最后 循环redefineArrayMethod 对应每一次下标循环 拿到都是一个数组方法关键字 第一次拿到’push’ 第二次’pop’

然后 我们的响应式代码就可以写在这里 首先 我们先

const backupFunction = arrayPrototype[item];

备份一下原来的方法 因为 你别重写之后 方法原有的逻辑没有了啊 是不是

你别说 push我监听一下 写完 push都加不进去东西了 那响应个啥 这BUG了啊

然后 我们调用def

第一个参数是 arrayMethods 就是被创建的对象

第二个 这里传的是 当前循环的内容 就是方法名数组下标 看着是第几次循环 第一次 push 第二次 pop 第三次 shift 依次类推

第四个参数 不用说 这东西你们肯定不希望他参与遍历吧 果断false 至于第三个 是他的值 我们要改写这个函数啊 就写了这个函数新的内容

backupFunction.apply(this, arguments);

先把我们备份的之前的函数内容执行了 就是 比如 push 我们先用执行参数帮他把push应该有的增加下标的逻辑执行了 this不用说 肯定要的 当前对象 然后arguments代表我们当前函数拿到的所有参数 全部给了backupFunction.apply当参数 就是保证参数不要少了

然后下面的代码 我们就捕获被改变的这个事情

然后 我们改写 dataResp.js中的Observer类代码如下

class Observer{
    constructor(value) {
        //相当于  给拿到的对象  其中的__ob__绑定 值为thsi,在类中用this 表示取实例本身给__ob__赋值  最后一个enumerable为false 表示属性不参与for遍历
        def(value,'__ob__',this,false);
        if(Array.isArray(value)){
            Object.setPrototypeOf(value, arrayMethods);
        }
        this.walk(value);
    }
    walk(value) {
        for(let key in value){
            defineReactive(value,key);
        }
    }
}

就是 监听到 如果是数字类型 调用一下 Object.setPrototypeOf 监听

然后 我们再次运行代码

在这里插入图片描述

可以看到 我们重写的方法 就起效了 push被成功捕获 并输出了语句

在这里插入图片描述

到此这篇关于vue数据响应式原理重写函数实现数组响应式监听的文章就介绍到这了,更多相关vue重写函数实现数组响应式监听内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java事务的个人理解小结

    Java事务的个人理解小结

    数据库操作的事务习惯上就称为Java事务
    2013-03-03
  • Springboot整合Gson报错问题解决过程

    Springboot整合Gson报错问题解决过程

    这篇文章主要介绍了Springboot整合Gson报错问题解决过程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-06-06
  • SpringBoot过滤器与拦截器深入分析实现方法

    SpringBoot过滤器与拦截器深入分析实现方法

    大家应该都晓得实现过滤器需要实现 javax.servlet.Filter 接口,而拦截器会在处理指定请求之前和之后进行相关操作,配置拦截器需要两步,本文通过实例代码给大家介绍SpringBoot 过滤器和拦截器的相关知识,感兴趣的朋友一起看看吧
    2022-11-11
  • Spring Cloud Feign统一设置验证token实现方法解析

    Spring Cloud Feign统一设置验证token实现方法解析

    这篇文章主要介绍了Spring Cloud Feign统一设置验证token实现方法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-08-08
  • JDBC数据库连接步骤解析

    JDBC数据库连接步骤解析

    这篇文章主要介绍了JDBC数据库连接步骤解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-02-02
  • Java语言通过三种方法实现队列的示例代码

    Java语言通过三种方法实现队列的示例代码

    这篇文章主要介绍了Java语言通过三种方法来实现队列的实例代码,数组模拟队列,通过对定义的了解,发现队列很像我们的数组,下面我们通过实践给大家详细介绍,需要的朋友可以参考下
    2022-02-02
  • SpringBoot使用Flyway进行数据库管理的操作方法

    SpringBoot使用Flyway进行数据库管理的操作方法

    Flyway是一个开源的数据库版本管理工具,并且极力主张“约定大于配置”,简单、专注、强大。接下来通过本文给大家介绍SpringBoot使用Flyway进行数据库管理的方法,感兴趣的朋友一起看看吧
    2021-09-09
  • java中String.matches方法使用

    java中String.matches方法使用

    String.matches()方法用于检测字符串是否符合特定的正则表达式,详细介绍了如何使用String.matches()配合不同的正则表达式来匹配各种特定格式的字符串,感兴趣的可以了解一下
    2024-09-09
  • MyBatis批量更新(update foreach)报错问题

    MyBatis批量更新(update foreach)报错问题

    这篇文章主要介绍了MyBatis批量更新(update foreach)报错问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-08-08
  • 解决SpringBoot使用yaml作为配置文件遇到的坑

    解决SpringBoot使用yaml作为配置文件遇到的坑

    这篇文章主要介绍了解决SpringBoot使用yaml作为配置文件遇到的坑,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08

最新评论