0

This doesn't work (in chrome 39 on OSX):

var x = new Image();
Object.observe(x, function(){console.log('i never run');})
x.src = 'http://www.foo.com';
console.log('has been set: ' + x.src);

But this will:

var x = new function nonNative(){};
Object.observe(x, function(){console.log('i will run');})
x.src = 'http://www.foo.com';

And so will this:

var x = new XMLHttpRequest();
Object.observe(x, function(){console.log('so will i');})
x.src = 'http://www.foo.com';

So the problem isn't related directly to Image being a native constructor (since XMLHttpRequest works as expected) - it seems to be something specific to setting img.src. I can only guess it's because setting an src behaves a lot like a method (in that it causes the request to be made). Is there such a thing in JS as a method which can be called like a property?

Assuming it's not that, does anyone know/can guess if this is desired behaviour of Object.observe (couldn't see anything in mdn docs), and if not, where might be the best place for me to report it as a bug?

Bergi
  • 513,640
  • 108
  • 821
  • 1,164
Sam Adams
  • 3,997
  • 2
  • 14
  • 16
  • It seems to me that the way (new Image()).src is behaving is a lot like how Object.observe() would behave (as in 'something' is detecting the change to the object). Maybe that has something to do with it... – Sam Adams Dec 11 '14 at 16:44

2 Answers2

1

x.src = is a sort of shorthand for x.setAttribute('src', ..., and setting attributes does not trigger Object.observe--this is the DOM world, not the JS object world. Attributes on HTMLElements are not JS object properties (although sometimes they pretend to be; actually they lurk within the attributes property as a NamedNodeMap), and JS object properties are what Object.observe observes. You can verify this by setting a non-attribute property on your image, and see the observer function firing.

Setting src on XMLHttpRequest works because XMLHttpRequest is just a plain old JS object and src is just a plain old property on it.

If you want to observe attribute changes, you can use mutation observers.

  • Thanks, good to know. Just out of interest, is it possible to replicate this behaviour in 'normal' JS? e.g. can i write my own object which will call a method when a property is assigned? I have looked at [proxy](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Proxy) but it seems it isn't widely supported yet. – Sam Adams Dec 12 '14 at 08:47
  • I think you are looking for the change type called `'add'` (when the property is assigned for the first time; if it already exists, then change type would be `'update'`). –  Dec 12 '14 at 09:22
0

As others have mentioned, src is not an attribute, it is a defined getter/setter pair, so by assigning it, you are actually calling a function.

Since this is a DOM element, you'd be better off using MutationObserver.

var x = new Image();
var observer = new MutationObserver(function(){
    console.log('i will run');
});

observer.observe(x, {attributes: true});

x.src = 'http://www.example.com.com'
loganfsmyth
  • 135,356
  • 25
  • 296
  • 231