DOM元素上的代理在返回实现接口Element的函数时会出错

时间:2015-01-16 11:30:52

标签: javascript dom proxy

我已经在DOM元素上设置了代理,在本例中是一个XUL元素<browser>。代理工作正常,除非我想返回某些需要元素实现接口元素的函数,否则我会收到错误。

我实际使用的代理更复杂,但减少了一些,我的测试代理如下:

let gB = {

  NS_XUL : "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  browser : document.createElementNS(this.NS_XUL, "browser"),

  addTab : function() {

    let tab = document.createElementNS(this.NS_XUL, "tab");

    tab.linkedBrowser = new Proxy(this.browser,{
      "get": function (target, key) {
        if (key in target) {
          return target[key];
        }
      },
    });
    return tab;
  },  
}

当我运行以下代码时:

let tab1 = gB.addTab()
try {
  dump("      1 > "+tab1.linkedBrowser.getBoundingClientRect()+"\n");
}catch(e) { dump("ERROR 1 : "+e+"\n"); }

我得到了这个输出:

ERROR 1 : TypeError: 'getBoundingClientRect' called on an object that does not implement interface Element.

对我来说非常令人费解的是,我可以直接在元素上运行相同的函数,并且没有错误,但我可以比较两个函数的相等性,并且它表明它们是完全相同的对象:< / p>

let tab1 = gB.addTab()
dump("equals? : "+(tab1.linkedBrowser.getBoundingClientRect === gB.browser.getBoundingClientRect)+"\n");
try {
  dump("      1 > "+tab1.linkedBrowser.getBoundingClientRect()+"\n");
}catch(e) { dump("ERROR 1 : "+e+"\n"); }
try {
  dump("      2 > "+gB.browser.getBoundingClientRect()+"\n");
}catch(e) { dump("ERROR 2 : "+e+"\n"); }

我得到了这个输出:

equals? : true
ERROR 1 : TypeError: 'getBoundingClientRect' called on an object that does not implement interface Element.
      2 > [object DOMRect]

相等测试显示它们是同一个对象,但是一个给出错误,另一个没有。

进一步的实验似乎表明问题与代理本身无关,而是与函数返回函数有关。它还揭示了该问题与XUL无关,因为在这种情况下我使用的是HTML元素:

我的代码:

let gB = {

  getFunction : function() {

    let div = document.createElement("div");
    return div.getBoundingClientRect;
  },  
}

当我跑步时:

try {
  dump("      1 > "+gB.getFunction()()+"\n");
}catch(e) { dump("ERROR 1 : "+e+"\n"); }

我再次得到:

ERROR 1 : TypeError: 'getBoundingClientRect' called on an object that does not implement interface Element.

我展示的代理示例大大减少了我想要完成的任务。我的工作代理用于根据所寻找的属性选择性地懒惰地创建复杂的DOM元素结构。即,如果访问tab.linkedBrowser.propertyA,则会运行一个函数来创建元素结构,但是如果访问tab.linkedBrowser.propertyB,则不会,而是返回一个替换值。

我很乐意获得有关如何返回使用界面并能够运行它们的这些函数的见解。

我也非常对关于等式测试如何显示两个不同的函数表达式引用它们相同的对象的解释感兴趣,但运行它们中的每一个都会产生不同的结果。

1 个答案:

答案 0 :(得分:1)

我认为它是Firefox中的错误。他们的方法不能用于除DOM Elements之外的任何东西,即使在继承对象时也是如此。我们必须等待完整的ES6实施。

我未经考验的主张是:

new Proxy(this.browser, {
    "get": function(target, key, receiver) {
        dump("GET : " + key + "\n");
        if (key in target) {
            let ret = target[key];
            if (typeof ret === 'function') {
                // DOM methods sometimes aren't istances of Function, so we can't directly use func.bind()
                ret = Function.prototype.bind.call(ret, target);
            }
            return ret;
        }
    },
});

至少有几点需要注意:

  • 方法将在this设置为原始对象的情况下调用。
  • 您无法使用===来测试方法是否已修改