Proxy object cannot be added to DOM (traps doesn't trigger either)

岁酱吖の 提交于 2021-01-26 09:46:42

问题


I am trying to make a Proxy object of Image to trap properties but even with an empty handler I get an error message.

TypeError: Argument 1 of Node.appendChild does not implement interface Node.

The proxy object is suppose to act as the target object so this baffles me a little. As far as I understand you should be able to do this with DOM nodes as well (?).

Also: I cannot start loading the image and have the onload handler triggered when setting the src property.

How should I use the Proxy so I can "take over" for example the "src" property and otherwise have it act like a regular image object?

My code

'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

Update: Thanks to @Harangue! using "new" (bah..) certainly made the proxy object come to life but now I am unable to trap the setting of properties. It seem to ignore the trap completely - example:

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';

How can I trap the property setting using a valid proxy?

Update 2 On the other hand - using new with the new proxy only seem to use the original constructor. All examples I can find does not use new:

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

Using then on top of that new myProxy() only seem to use the original constructor which is not what I want as it ignores the traps.

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

The traps seem to work in my first attempts but the proxy doesn't behave as expected. This is so confusing, and so new. Happy for any input how both of these can be solved (traps and behavior).


回答1:


Never underestimate the importance of the new keyword. ;)

//--- 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

With the proxy you effectively extend the Image object. But sending the Image constructor itself, rather than the DOM Node returned by it, would indeed be missing the needed appendChild.




回答2:


As an alternative to a proxy you can also overwrite the property on the object itself and therefore control it's behaviour:

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

And since this property is defined on the Image.prototype*, you can simply extend this class and modify the behaviour on the prototype of the inherited Class

*at least in FF, have to check the other browsers



来源:https://stackoverflow.com/questions/38802193/proxy-object-cannot-be-added-to-dom-traps-doesnt-trigger-either

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!