覆盖对象原型并禁止任何进一步的覆盖

时间:2017-11-14 21:50:08

标签: javascript

我试图编写一个拦截所有XMLHttpRequest调用的库,并在最终通过覆盖其原型之前做一些事情,例如:

var original_open = XMLHttpRequest.prototype.open;    
XMLHttpRequest.prototype.open = function() {
    // my own override logic here before running the original function
    original_open.apply(this, arguments);
};

问题是,我想保证当有人使用此库时,网页上的任何其他代码都无法重新覆盖此效果。

因为否则,使用此库的网站可以动态加载另一段JS代码,它只会再次覆盖XMLHttpRequest.prototype.open,而这个库的全部目的是禁止它。

我想在覆盖之后立即使用Object.freeze()冻结原型,这样其他代码就无法覆盖我自己的覆盖。代码看起来像这样:

var original_open = XMLHttpRequest.prototype.open;    
XMLHttpRequest.prototype.open = function() {
    // my own override logic here before running the original function
    original_open.apply(this, arguments);
};
Object.freeze(XMLHttpRequest.prototype);

我的期望是,如果同一页面上的另一段代码试图重新覆盖我自己的覆盖,它将失败,因为原型已被冻结。

我的问题:

  1. 这是解决此问题的正确方法吗?
  2. 这真的很安全吗? (没有漏洞)?

1 个答案:

答案 0 :(得分:1)

不要冻结原型。这会导致开发人员感到沮丧,无法解释的错误以及没有人使用您的库。您无法知道其他库将修改该方法,以及它们将如何执行此操作,从而导致您编写无穷无尽的边缘情况。坚持最佳实践,并假设开发人员正在进行明智,兼容的库选择。

由于客户端代码的性质,您必须假设其他专业图书馆将遵循最佳做法。如果5个库都使用您使用的约定修改原型方法,则所有5个库将一起工作。

例如,这两个覆盖只是一起工作:



var old1 = Document.prototype.querySelector;
Document.prototype.querySelector = function(...args) {
  console.log('Override 1');
  return old1.call(this, ...args);
};

var old2 = Document.prototype.querySelector;
Document.prototype.querySelector = function(...args) {
  console.log('Override 2');
  return old2.call(this, ...args);
};

let p = document.querySelector('body');

console.log(p);