[转载]JavaScript中移除由addEventListener添加的匿名函数 | 祭夜博客
  • 欢迎光临,这个博客颜色有点多

[转载]JavaScript中移除由addEventListener添加的匿名函数

JavaScript msojocs 来源:JavaScript中移除由addEventListener添加的匿名函数 2年前 (2022-01-22) 1388次浏览 已收录 0个评论 扫描二维码

JavaScript中移除由addEventListener添加的匿名函数
强行篡改闭包xhr对象的返回值

花生个人一直比较喜爱Js,喜爱它的高灵活 喜欢它的……

本文章主要采用的技术叫做“函数劫持”,有兴趣的同学可以自学百度。

话不多说,开始!

如果想要直接要代码参考的请直接翻到最后。

在群里有一个群友表示自己需要篡改某网站的xhr对象返回值(responseText),而xhr对象的responseText属性是只读的,这个可如何是好?

于是花生提议你可以这样:


window.addEventListener('load',function(){
    var xhr=new XMLHttpRequest();
    xhr.open('get','sleep.php?sleep=1',true);
    xhr.onreadystatechange = function(e){
        if (this.readyState == 4 && this.status == 200){
            console.log("Ajax成功返回:"+this.responseText)
        };
    };
    xhr.send();
    //开始篡改
    xhr.abort();
    var obj={'readyState':4,'status':200,'responseText':'篡改'};
    xhr.onreadystatechange.call(obj);
},false);

但是他说原网站的xhr写在闭包里了,大约是这样

window.addEventListener('load',function(){
    (function(){
        var xhr=new XMLHttpRequest();
        var dv1=document.getElementById('dv1');
        xhr.open('get','sleep.php?sleep=1',true);
        xhr.addEventListener('readystatechange', function(e){
            if (this.readyState == 4 && this.status == 200){
                console.log("Ajax成功返回:"+this.responseText)
            };
        },false);
        dv1.addEventListener('click',function(){
            xhr.send();
        },false);
    })();
},false);

原网站不仅仅是把xhr写在闭包里,还用addEventListener来添加事件,而且添加的还是匿名函数,嘿嘿嘿,我看你怎么办

各种查手册,w3c、Mozilla都看了,它们一致的告诉花生:想捕获addEventListener?门都没有!

简直就是在逼花生放大招!

在开头加入

window.pro_xhr_addEventListener=XMLHttpRequest.prototype.addEventListener
XMLHttpRequest.prototype.addEventListener=function(){
    //做你想做的事情
    //do sth
    //保证原有功能
    window.pro_xhr_addEventListener.apply(this,arguments);
};

注意,这里我只是想监视xhr的addEventListener方法调用,如果读者需要监视dom节点,将开头的XMLHttpRequest替换成Element即可。

问题到这里差不多就结束了,但是猛然发现,监视xhr的addEventListener并没有什么判断条件,花生想要通过xhr的发送地址来判断是否做出什么动作,比如

XMLHttpRequest.prototype.addEventListener=function(){
    if(this.url == 'sleep.php?sleep=1'){
        //do sth
    };
    //保证原有功能
    window.pro_xhr_addEventListener.apply(this,arguments);
};

各种查手册,w3c、Mozilla都看了,它们还是一致的告诉花生:并没有什么属性可以直接获取到xhr的url……

好吧,再放一次大招好了

window.pro_xhr_open=XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open=function(){
    this.pea=new Object();
    this.pea.allArguments=arguments;
    this.pea.method=arguments[0];
    this.pea.url=arguments[1];
    this.pea.async=arguments[2];
    this.pea.username=arguments[3];
    this.pea.password=arguments[4];
    //保证原有功能
    window.pro_xhr_open.apply(this,arguments);
};

这次是重写了open方法,让每次调用xhr.open的时候,将open使用的参数全部暴露出来。

而最后的demo差不多就是像下面这样,按照群友的需求,要把1234567890123变成xyz4567890xyz(真是奇怪的需求)

好吧,那么修改下根目录下的sleep.php,让它返回1234567890123

[转载]JavaScript中移除由addEventListener添加的匿名函数

好吧,接下来是实现代码

window.onload=function(){
    window.pro_xhr_open=XMLHttpRequest.prototype.open;
    XMLHttpRequest.prototype.open=function(){
        this.pea=new Object();
        this.pea.allArguments=arguments;
        this.pea.method=arguments[0];
        this.pea.url=arguments[1];
        this.pea.async=arguments[2];
        this.pea.username=arguments[3];
        this.pea.password=arguments[4];
        //保证原有功能
        window.pro_xhr_open.apply(this,arguments);
    };
 
    window.pro_xhr_addEventListener=XMLHttpRequest.prototype.addEventListener
    XMLHttpRequest.prototype.addEventListener=function(){
        if(this.pea.url == 'sleep.php?sleep=1' && arguments[0]=== 'readystatechange'){
            var that=this;
            var old_callback=arguments[1];
            var fakeObj={'readyState':4,'status':200};
 
            arguments[1]=function(){
                if (this.readyState == 4 && this.status == 200){
                    fakeObj.responseText=this.responseText.replace(/123/g,'xyz');
                    old_callback.call(fakeObj);
                }else{
                    arguments[1]=old_callback;
                };
            };
        }
        //保证原有功能
        window.pro_xhr_addEventListener.apply(this,arguments);
    };
 
    (function(){
        var dv1=document.getElementById('dv1');
        var xhr=new XMLHttpRequest();
        xhr.open('get','sleep.php?sleep=1',true);
        xhr.addEventListener('readystatechange', function(e){
            if (this.readyState == 4 && this.status == 200){
                console.log("Ajax成功返回:"+this.responseText)
            };
        },false);
        dv1.addEventListener('click',function(){
            xhr.send();
        },false);
    })();
}

这样,返回值就变成了xyz4567890xyz,注意,URL里面的sleep=1只是为了方便if判断,仅此而已

好了,问题解决了

等等,好像本文到现在还是没有实现“JavaScript中移除由addEventListener添加的匿名函数”啊!

好吧,如果真的是一路看下来应该都可以自己写了,不过这里还是给出代码参考

这里的需求是,移除掉ID为dv1的DIV的第二个click绑定事件,下面的是原文件

<div id="dv1" style="width:300px;height:300px;background:red;">dv1</div>
 
<script>
    var dv1=document.getElementById('dv1');
 
    dv1.addEventListener('click',function(){
        alert(this.innerHTML);
    });
 
    dv1.addEventListener('click',function(){
        alert(this);
    });
</script>

下面的修改文件,注意,重写js原有方法部分需要放在文件最开始,要不然会监视不到

<div id="dv1" style="width:300px;height:300px;background:red;">dv1</div>
 
<script>
    //重写js原有方法
    window.pro_elt_addEventListener=Element.prototype.addEventListener;
    Element.prototype.addEventListener=function(){
        if(!this.eventList) this.eventList={};
        if(!this.eventList[arguments[0]]) this.eventList[arguments[0]]=[];
        this.eventList[arguments[0]].push(arguments[1]);
        window.pro_elt_addEventListener.apply(this,arguments);
    };
    //原文件
    var dv1=document.getElementById('dv1');        
    dv1.addEventListener('click',function(){    
        alert(this.innerHTML);
    });        
    dv1.addEventListener('click',function(){       
        alert(this);
    });
    //输出绑定的事件列表
    alert(dv1.eventList.click.join('\n'));
    //移除事件
    dv1.removeEventListener("click",dv1.eventList.click[1]);
</script>

好了,本来打算封装一个好用的类来快捷的完成这个操作,想想用到的很少,还是算了。。。

参考资料:

http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventListener

https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest


祭夜の咖啡馆 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:[转载]JavaScript中移除由addEventListener添加的匿名函数
喜欢 (4)
[1690127128@qq.com]
分享 (0)

您必须 登录 才能发表评论!