views:

118

answers:

4

A web page of a web application was showing a strange error. I regressively removed all the HTML/CSS/JS code and arrived to the basic and simple code below.

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"&gt;
<html><head>
<title>test</title>

   <script type="text/javascript">
      var TestObj =
      {
         foo: function() {}
      }

      alert(x); //ok displays "undefined"
      var x = TestObj.foo;
      var z = TestObj.foo;
    </script>

</head><body>

   <p onclick='alert(x);'>Click shows function foo!</p>
   <img onclick='alert(x);' alt='CRAZY click displays a number in FF/Safari not function foo' src='' style='display: block; width: 100px; height: 100px; border: 1px solid #00ff00;'>
   <p onclick='alert(x);'>Click shows function foo!</p>

</body></html>

It's crazy: when clicking on P elements the string "function(){}" is displaied as expected. But when clicking on IMG element it shows a number as if x function got in some way removed from memory or deinstantiated (it does not even show x as "undefined" but as a number).

To let you test it quickly I placed the working test above also here.

This can be reproduced on both Firefox 3.6 and Safari 4.0.4.

Everything works properly only on IE7+.

I'm really clueless, I was wondering if x is maybe a reserved keyword in JS Firefox/Safari. Thanks to anyone who could help!

FYI:

  1. if you repalce x() with z() everything work prefectly in all browsers (this is even more crazy to me)
  2. adding a real image in src attribute does not fix the problem
  3. removing style in img does not fix the problem (i gave style to image only to help you clicking on image thus you can see the imnage border)
+6  A: 

Your problem is with variable scope, not that "x" is reserved. An image object has a property named "x". You can see this with Chrome's developer tools. When you call "alert(x);" on the image object, the "x" in scope is the "x" property on the image.

David
The `x` property seems to be the x-coordinate of the image; `y` is what you would expect, too.
Matchu
Ah yes, beat me too it. This is what I was thinking too. But I haven't been able to find any official documentation of this behavior. Presumably the functionality is just left over from the "DOM 0" days?
Daniel Pryden
@David: if I was an artist I would build a statue to you and to stackoverflow. I really, really appreciated your help, I was nearly beating my head on the desk today! Thanks!
Marco Demajo
+1  A: 

I can't seem to find any documentation to support this, but my guess is that the <img> tag is being treated specially, and the object is actually a JavaScript Image object, not a normal DOM element. The Image object has an x property, and so your unscoped reference to x means Image.x. If you want the global x property, just use window.x instead.

Daniel Pryden
A: 

Still supported by some browsers, before the dom spec, images, a elements and area elements all had read only x and y properties for their coordinates on the page.

kennebec
+1  A: 

Just to complete the answers from David and Daniel, this behavior is not documented at all, but it work like the following in almost every modern browser:

The content of an inline event handler becomes the FunctionBody of a function that the browser calls when it fires that event.

The scope chain of this function is augmeted with the element, the element's FORM (if it exits and is a FORM element), and document itself.

It looks something like this in code:

function onclick(event) {
  with(document) {
    with(this.form) {
      with(this) {
        // inline event handler content...
      }
    }
  }
}

This behavior can cause all sort of name conflicts due the augmentation of the scope chain you cannot be 100% sure about what you are referring, it could be an attribute of the element itself, an attribute of the element's form, an attribute of the document object or any global variable.

Recommended article:

CMS