未定义JavaScript-addEventListener

未定义JavaScript-addEventListener,javascript,google-chrome,google-chrome-extension,ecmascript-6,ecmascript-2016,Javascript,Google Chrome,Google Chrome Extension,Ecmascript 6,Ecmascript 2016,我正在创建一个阻止广告的chrome扩展。到目前为止,一切都很好。我的目标是: 禁用WebSocket 禁用控制台日志 禁用警报 禁用弹出窗口(窗口。打开) 在卸载之前禁用on 当然,它应该只在指定的网站上阻止这些功能。我搜索了如何阻止函数。我发现使用扩展禁用函数的唯一方法是 在manifest.json中添加一个内容脚本init.js,该脚本将在document\u start处运行(这将防止在我的扩展代码之前执行任何其他代码,因此在我禁用这些函数之前,没有人可以窃取并保存对它们的引用) 从i

我正在创建一个阻止广告的chrome扩展。到目前为止,一切都很好。我的目标是:

  • 禁用
    WebSocket
  • 禁用控制台日志
  • 禁用
    警报
  • 禁用弹出窗口(
    窗口。打开
  • 在卸载之前禁用
    on
  • 当然,它应该只在指定的网站上阻止这些功能。我搜索了如何阻止函数。我发现使用扩展禁用函数的唯一方法是

  • manifest.json
    中添加一个内容脚本
    init.js
    ,该脚本将在
    document\u start
    处运行(这将防止在我的扩展代码之前执行任何其他代码,因此在我禁用这些函数之前,没有人可以窃取并保存对它们的引用)
  • init.js
    在网页中插入代码,以便我的扩展可以访问非沙盒环境
  • 覆盖黑名单函数
  • 我做了所有的事情,但问题是如何重写函数。我在ECMAScript 7规范中发现,无法检测函数是否为代理实例。因此,我对这些函数进行了代理验证,它按预期工作。网站没有注意到我已经覆盖了所有这些功能

    但是,它适用于除
    addEventListener
    之外的所有函数。为了阻止
    onbeforeunload
    ,我应该向它添加一个代理处理程序,并跟踪调用以检查侦听器名称是否为
    onbeforeunload
    。我写了以下脚本:

    addEventListener = new Proxy(addEventListener, {
      apply: (f, t, args) => {
        if(args[0] !== 'onbeforeunload'){
          f.apply(t, args);
        }
      }
    });
    
    这将筛选调用,并仅允许未设置
    onbeforeunload
    事件的调用。但是,它抛出引用错误:未定义addEventListener。这让我很吃惊。我想这可能是因为
    addEventListener
    尚未在
    document\u start
    初始化,而是console.log(addEventListener的类型)
    函数
    记录到控制台。这怎么可能呢

    我无法解释。但是,我尝试将其放入一个函数中,然后对该函数执行
    requestAnimationFrame
    ,直到
    addEventListener
    变得可访问为止(我在
    try…catch
    中重新封装了上述代码)。但是,事实证明,修改
    addEventListener
    总是抛出ReferenceError,而仅仅访问不会抛出错误

    我还尝试从开发者控制台和
    javascript:…
    方法访问它,但它的行为正常,我可以修改它而不会出现任何错误

    编辑 当然,问题与
    不同,因为我正确地将脚本
    注入了非沙盒(真实)页面环境,并且我可以访问真实的
    窗口
    对象。

    addEventListener
    实际上不是全局的,而是间接的。它是
    EventTarget.prototype
    (至少在Chrome中)的一个属性<代码>窗口的原型链中有
    EventTarget.prototype
    ,这使得
    addEventListener
    成为一个全局变量

    因此,您需要粗略地代理它(无需检查事件名称,仅用于演示):

    const save=EventTarget.prototype.addEventListener;
    EventTarget.prototype.addEventListener=新代理(保存{
    应用:函数(目标、此参数、参数){
    console.log(“Foo!”);
    返回save.apply(thisArg,args);
    }
    });
    document.body.addEventListener(“单击”,函数(){
    控制台日志(“单击”);
    });
    

    addEventListener
    实际上不是全局的,而是间接的。它是
    EventTarget.prototype
    (至少在Chrome中)的一个属性<代码>窗口
    的原型链中有
    EventTarget.prototype
    ,这使得
    addEventListener
    成为一个全局变量

    因此,您需要粗略地代理它(无需检查事件名称,仅用于演示):

    const save=EventTarget.prototype.addEventListener;
    EventTarget.prototype.addEventListener=新代理(保存{
    应用:函数(目标、此参数、参数){
    console.log(“Foo!”);
    返回save.apply(thisArg,args);
    }
    });
    document.body.addEventListener(“单击”,函数(){
    控制台日志(“单击”);
    });
    

    我不知道您这样做是否会遇到问题,也不知道您的整体方法是否会起作用(祝您好运!),但这就是为什么您会在
    addEventListener
    …-)中遇到错误的原因还有一个问题。您如何解释修改
    addEventListener
    会在定义时抛出
    ReferenceError
    ,我可以访问它,但不能修改它?@jumpjet\uuuuu我不确定您为什么会得到这样的结果。当我在普通的Chrome窗口中尝试它时,我不知道。顺便说一句,我之前没有想到,
    addEventListener
    是全局的,因为
    window
    继承了
    EventTarget.prototype
    :-)但是分配给
    窗口
    的版本并不能处理任何地方的更新。我不知道这样做是否会遇到问题,也不知道您的整体方法是否有效(祝您好运!),但这就是为什么您在
    addEventListener
    …-)上出现错误的原因还有一个问题。您如何解释修改
    addEventListener
    会在定义时抛出
    ReferenceError
    ,我可以访问它,但不能修改它?@jumpjet\uuuuu我不确定您为什么会得到这样的结果。当我在普通的Chrome窗口中尝试它时,我不知道。顺便说一句,我之前没有想到,
    addEventListener
    是全局的,因为
    window
    继承了
    EventTarget.prototype
    :-)但是分配给
    窗口的版本将无法在任何地方更新它。为什么要禁用sockets和console.log?@DanielHerr。许多网站通过
    WebSockets
    image:data
    的形式传输广告。斯坦达