You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何重写(MonkeyPatch)document/Element的querySelector并恢复及修复异常?

问题分析与修复方案

错误根源

  1. 上下文绑定错误:你把querySelector绑定到了Element构造函数而非元素实例,调用时this指向混乱,直接触发「Illegal invocation」错误。
  2. 恢复逻辑失误:maybeOverrideForTestEnd里取Element.querySelectorTemp是错的,备份方法存在Element.prototype上,得从原型链上取。
  3. 覆盖范围不全:document属于Document类型,不是Element实例,原代码只覆盖了普通元素(包括document.body)的querySelector,没覆盖document本身的方法。

修复后的代码

function maybeOverrideForTestStart(partialIDOfWidget, fullIDOfWidget) {
  if (!isLocal) return;
  const addonID = fullIDOfWidget.replace(partialIDOfWidget, "");
  
  // 备份原生方法,不提前绑定上下文
  Element.prototype._originalQuerySelector = Element.prototype.querySelector;
  Document.prototype._originalQuerySelector = Document.prototype.querySelector;

  // 重写Element实例的querySelector
  Element.prototype.querySelector = function(selector) {
    let element = this._originalQuerySelector(selector);
    if (element) return element;
    if (addonID) {
      return this._originalQuerySelector(selector + addonID) || null;
    }
    return null;
  };

  // 同步重写Document的querySelector(适配document.querySelector)
  Document.prototype.querySelector = function(selector) {
    let element = this._originalQuerySelector(selector);
    if (element) return element;
    if (addonID) {
      return this._originalQuerySelector(selector + addonID) || null;
    }
    return null;
  };
}

function maybeOverrideForTestEnd() {
  if (!isLocal) return;
  // 安全恢复原生方法并清理备份
  if (Element.prototype._originalQuerySelector) {
    Element.prototype.querySelector = Element.prototype._originalQuerySelector;
    delete Element.prototype._originalQuerySelector;
  }
  if (Document.prototype._originalQuerySelector) {
    Document.prototype.querySelector = Document.prototype._originalQuerySelector;
    delete Document.prototype._originalQuerySelector;
  }
}

关键改进点

  • 保留正确上下文:直接调用备份方法,利用函数调用时的this自动绑定当前元素/文档实例,避免绑定错误。
  • 覆盖完整场景:同时重写Document和Element的原型方法,确保document.querySelector、document.body.querySelector、普通元素的querySelector全部生效。
  • 规范返回值:补全无匹配时的null返回,和原生方法行为保持一致。
  • 安全清理:恢复后删除备份属性,避免污染原型链,增加存在性判断防止重复调用报错。

覆盖范围说明

  • 原代码仅对所有Element实例生效(比如document.body、各类DOM元素),document本身的querySelector不受影响。
  • 修复后的代码同时覆盖Element和Document类型,所有调用querySelector的场景都会触发重写逻辑。

内容的提问来源于stack exchange,提问作者romand

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 04:46:33