【问题标题】:Proxy object cannot be added to DOM (traps doesn't trigger either)无法将代理对象添加到 DOM(陷阱也不会触发)
【发布时间】:2016-12-12 15:13:12
【问题描述】:

我正在尝试制作 Image 的 Proxy object 来捕获属性,但即使使用空处理程序,我也会收到错误消息。

TypeError:Node.appendChild 的参数 1 没有实现接口 Node。

代理对象应该充当目标对象,所以这让我有点困惑。据我了解,您应该也可以使用DOM nodes 执行此操作(?)。

另外:我无法开始加载图像并且在设置src 属性时触发了onload 处理程序。

我应该如何使用代理,以便我可以“接管”例如“src”属性,否则它就像一个普通的图像对象?

我的代码

'use strict';

//--- normal image use ---
var imgNormal = new Image();
imgNormal.onload = function(){
  console.log('Normal loaded OK');
  document.body.appendChild(imgNormal);
};
imgNormal.src = 'https://i.imgur.com/zn7O7QWb.jpg';

//--- proxy image ---
var imgProxy = new Proxy(Image, { // I also tried with 'new Image()' and HTMLImageElement
  set: function(a,b,c,d){
    console.log('set '+b);
    return Reflect.set(a,b,c,d);
  }
});
imgProxy.onload = function(){
  console.log('Proxy loaded OK');
  document.body.appendChild(imgProxy);
};
imgProxy.src = 'https://i.imgur.com/zn7O7QWb.jpg';

document.body.appendChild(imgProxy); // double-up to demo error

更新:感谢@Harangue! 使用 "new" (bah..) 确实使代理对象变得栩栩如生,但 现在我无法捕获属性设置。它似乎完全忽略了陷阱-示例:

var proxy = new Proxy(Image, {
      set: function(a,b,c,d){
        console.log('set '+b);        // doesn't show
        return Reflect.set(a,b,c,d);
      }
    });

    var imgProxy = new proxy();
    imgProxy.onload = function(){
      console.log('Proxy loaded OK');
      document.body.appendChild(imgProxy);
    };
    imgProxy.src = 'https://i.imgur.com/zn7O7QWb.jpg';

如何使用有效的代理来捕获属性设置?

更新 2 另一方面 - 使用带有 new 代理的 new 似乎只使用 original 构造函数。我能找到的所有示例不都使用新的:

var myProxy = new Proxy(.., ..);  // should suffer

在 new myProxy() 之上使用 then 似乎只使用原始构造函数,这不是我想要的,因为它忽略了陷阱。

var proxy = new Proxy(Image, {}); //should be sufficent??
var proxy2 = new proxy();
console.log(proxy2); //-> says Image (not proxy..)

陷阱似乎在我的第一次尝试中起作用,但代理的行为不如预期。这太令人困惑了,太新奇了。对于如何解决这两个问题(陷阱和行为)的任何输入,我们都很高兴。

【问题讨论】:

    标签: javascript ecmascript-6 javascript-objects es6-proxy


    【解决方案1】:

    作为代理的替代方案,您还可以覆盖对象本身的属性,从而控制其行为:

    function findDescriptor(obj, prop){
        if(obj != null){
            return Object.hasOwnProperty.call(obj, prop)?
                Object.getOwnPropertyDescriptor(obj, prop):
                findDescriptor(Object.getPrototypeOf(obj), prop);
        }
    }
    
    var img = new Image();
    var {get, set} = findDescriptor(img, "src");
    
    Object.defineProperty(img, "src", {
        configurable: true,
        enumerable: true,
    
        //get: get,  //keep behaviour
        get(){       //overwrite getter
            var v = get.call(this);  //call the original getter
            console.log("get src:", v, this);
            return v;
        },
    
        //same for setter
        set(v){
            console.log("set src:", v, this);
            //modify value before applying it to the default setter
            v = v.toLowerCase();
            set.call(this, v);
        }
    });
    
    img.src = "FileWithUppercaseLetters.jpg"; //setter
    img.src;  //trigger getter
    

    而且由于这个属性是在Image.prototype*上定义的,你可以简单地扩展这个类并修改继承类的原型上的行为

    *至少在FF中,必须检查其他浏览器

    【讨论】:

    • 谢谢!这绝对是我会想到的替代方案。我无法覆盖属性,这就是我查看代理的原因。不知道你可以这样做。不错!
    【解决方案2】:

    永远不要低估new 关键字的重要性。 ;)

    //--- proxy image ---
    var imgProxy = new Proxy(Image, {  // I also tried with 'new Image()'
      set: function(a,b,c,d){
        console.log('set '+b);
        return Reflect.set(a,b,c,d);
      }
    });
    imgProxy.src = 'https://i.imgur.com/zn7O7QWb.jpg';
    
    document.body.appendChild(new imgProxy); // double-up to demo error
    

    使用代理可以有效地扩展 Image 对象。但是发送 Image 构造函数本身,而不是它返回的 DOM 节点,确实会缺少所需的appendChild。

    【讨论】:

    • 啊,是的,我确实忘记了 new 关键字。但是,现在有一个新问题,因为我无法捕获设置。我在这里忽略了另一件事吗?我用该案例的新示例更新了答案。谢谢!
    • OTOH.. 在研究了示例之后,这似乎不是使用代理的常用方法。我的意思是,似乎 new Proxy(...) 应该足够了。您确定需要“新”吗?它似乎只是使用 Image 的构造函数而不通过代理。但我可能会误解。 ://
    • @bjanes 当我使用该代码时,只要设置了src,我就会收到一条控制台消息。您是否在寻找不同的行为?
    • 好的,我想我明白了……我基本上已经按照我的意愿设置了代理在实例化它之前。知道了!谢谢,我会再玩这个。
    猜你喜欢
    • 2015-11-28
    • 2018-09-14
    • 1970-01-01
    • 2013-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多