Perfection Kills

by kangax

Exploring Javascript by example

JScript and DOM changes in IE9 preview 3

June 24th, 2010

3rd preview of IE9 was released yesterday, with some amazing additions, like canvas element and an extensive ES5 support. I’ve been digging through it a little, to see what has changed and what hasn’t — mainly looking at JScript and DOM. I posted some of the findings on twitter, but want to also list them here, as it’s not very convenient to share code snippets in 140 characters. Referencing it all in one place will hopefully make it easier for IE team to find and fix these deficiencies.

ECMAScript 5 and JScript

The big news is that IE9pre3 has (almost) full support for ES5. By “full support”, I mean that it implements majority of new API, such as Object.create, Object.defineProperty, String.prototype.trim, Array.isArray, Date.now, and many other additions. As of now, IE9 implements the largest number of new methods; even more than latest Chrome, Safari and Firefox. Unbelievable, isn’t it? :)

screenshot of es5 compatibility table

You can see the results in this compatibility table (note that it lists results of mere “existence” testing, not any kind of conformance).

What’s missing is strict mode, which actually isn’t implemented in any of the browsers yet.

Some of the things I noticed:

ES5 Object.getPrototypeOf on host objects seems to lie, always returning null instead of proper value of [[Prototype]]:


  Object.getPrototypeOf(document.body); // null
  Object.getPrototypeOf(document); // null
  Object.getPrototypeOf(alert); // null
  Object.getPrototypeOf(document.childNodes); // null

This doesn’t happen in other browsers that implement Object.create at the moment, such as latest Chrome, WebKit or Firefox. In Chrome, for example:


  Object.getPrototypeOf(document.body) === HTMLBodyElement.prototype;
  Object.getPrototypeOf(document) === HTMLDocument.prototype;
  Object.getPrototypeOf(alert) === Function.prototype;
  Object.getPrototypeOf(document.childNodes) === NodeList.prototype

… and so on.

Interestingly, bound functions in IE9pre3 are represented as “function(){ [native code] }”, similar to host objects:


  var bound = (function f(x, y){ return this; }).bind({ x: 1 });
  bound + ''; // "function(){ [native code] }"

  // compare to

  alert + ''; // "function alert(){ [native code] }"

Note how function representation does not include identifier (f), parameters (x and y), nor representation of function body (return this;). This of course proves once again that relying on function decompilation is NOT a good idea.

Whitespace character class (as in /\s/) still doesn’t match majority of whitespace characters (as defined by specs). These include “U+00A0”, “U+2000” to “U+200A”, “U+3000”, etc. The test is available here. Curiously, ES5 String.prototype.trim seems to “understand” those characters as whitespace very well, producing empty string — as expected — for something like '\u00A0'.trim().

It was nice to see that ES5 Array.isArray is about 20 times faster than custom implementation, such as this one:


  function isArray(o) {
    return Object.prototype.toString.call(o) === "[object Array]";
  }

The difference in speed is similar to other browsers that implement this method.

An infamous, 10+ year-old JScript NFE bug, which I described at length before, is finally fixed:


  var f = function g() { return f === g; };
  typeof g; // "undefined"

  f(); // true

arguments’ [[Class]] is now an “Arguments”, just like ES5 specifies it:


  var args = (function(){ return arguments; })();
  Object.prototype.toString.call(args); // "[object Arguments]"

DOM

Unfortunately, the entire host objects infrastructure still looks very similar to the one from IE8. Host objects don’t inherit from Object.prototype, don’t report proper typeof, and don’t even have basic properties like “length” or “prototype”, which all function objects must have:


  alert instanceof Object; // false
  typeof alert; // "object"
  alert.length; // undefined

Because they don’t inherit from Object.prototype, we don’t have any of Object.prototype methods, naturally:


  alert.toString; // undefined
  alert.constructor; // undefined
  alert.hasOwnProperty; undefined

Object.prototype is not the only object host methods fail to inherit from. In majority of modern browsers, host objects also inherit from Function.prototype and so have Function.prototype methods like call and apply. This doesn’t happen in IE9pre3.


  alert instanceof Function; // false
  document.createElement instanceof Function; // false

  alert.call; // undefined

Curiously, call and apply are present on some host objects, but they are still not inherited from Function.prototype:


  typeof document.createElement.call; // "function"
  document.createElement.call === Function.prototype.call; // false

Host objects’ [[Class]] is far from ideal as well. IE9pre3 actually violates ES5, which says that objects implementing [[Call]] (or in other words — are callable) should have [[Class]] of “Function” — even if they are host objects. In IE9pre3, alert is a callable host object, yet it reports its [[Class]] as “Object” not “Function”. Not good.


  Object.prototype.toString.call(alert); // "[object Object]"
  Object.prototype.toString.call(document.createElement); // "[object Object]"

IE9pre3 still messes up DOM objects’ attributes and properties, although not as badly as earlier versions:


  var el = document.createElement('p');
  el.setAttribute('x', 'y');
  el.x; // 'y'

  el.foobarbaz = 'moo';
  el.hasAttribute('foobarbaz'); // true
  el.getAttribute('foobarbaz'); // 'moo'

Some old, humorous bugs can still be seen in IE9pre3, such as methods returning “string” when applied typeof on:


  typeof Option.create; // "string"
  typeof Image.create; // "string"
  typeof document.childNodes.item; // "string"

Undeclared assignments still throw error when same-id’ed elements are present in DOM, however not with same-name’ed elements (as it was in previous versions):


...

Similarly to IE8, only Element and specific element type interfaces (HTMLDivElement, HTMLScriptElement, HTMLSpanElement, etc.) are exposed as same-named global properties. Node and HTMLElement are still missing, and element’s prototype chain most likely still looks like this:


  document.createElement('div');
    |
    | [[Prototype]]
    v
  HTMLDivElement.prototype
    |
    | [[Prototype]]
    v
  Element.prototype
    |
    | [[Prototype]]
    v
  null

…rather than what can be seen in almost all other modern browsers:


  document.createElement('div');
    |
    | [[Prototype]]
    v
  HTMLDivElement.prototype
    |
    | [[Prototype]]
    v
  HTMLElement.prototype
    |
    | [[Prototype]]
    v
  Element.prototype
    |
    | [[Prototype]]
    v
  Node.prototype
    |
    | [[Prototype]]
    v
  Object.prototype
    |
    | [[Prototype]]
    v
  null

getComputedStyle from DOM Level 2 is still missing, however its value is mysteriously a null, not undefined. The property actually exists on an object, but has a value of null. Hopefully, this is just a placeholder and proper method will be added before final release.


  document.defaultView.getComputedStyle; // null
  'getComputedStyle' in document.defaultView; // true

Array.prototype.slice can now convert certain host objects (e.g. NodeList’s) to arrays — something that majority of modern browsers have been able to do for quite a while:


  Array.prototype.slice.call(document.childNodes) instanceof Array; // true

That’s it for now.

Unfortunately, I don’t have much time to look into these things extensively, at the moment. There might be more updates on twitter.

As always, any corrections, suggestions, and additions are much appreciated.

Categories: ECMA-262, isArray, review, strict-mode, [[Class]]

Comments (25)

  1. Gravatar

    Mathias said on Jun 24, 2010 @ 10:02

    Excellent research! I hope the IE team is reading this. Perhaps it’s a good idea to file the bugs you described in their bug tracker?

  2. Gravatar

    Bernhard H. said on Jun 24, 2010 @ 10:46

    Are these IE bugs or is it legal for Host objects not to implement these?

    I hope the Firefox team is reading this too… and what about Webkit?

  3. Gravatar

    Diego Perini said on Jun 24, 2010 @ 11:49

    Great informations in advance as always on the upcoming IE9.

    About the “getComputedStyle()” DOM2 method, it seems missing and as you said “is mysteriously a null”.

    However, if you do:

    alert(document.defaultView.getComputedStyle(document.body, null).getPropertyValue)

    it will return:

    function getPropertyValue() { [native code] }

    So your suspect about it being a (shadowed) placeholder for future DOM2 compatibility addition seems adequate.

    There is more to this, the “getPropertyValue()” method works, but only with “camelCased” property names (great vintage stuff from Visual Basic era). Maybe this could be the reason they still didn’t open up that path.

    See more on these tests in my tweets around (4th May) this and previous one:

    http://twitter.com/diegoperini/status/13365990466

    Also happy to see IE9 implements the same “[native code]” representation for native functions ;-)

    Keep up this fantastic and specialized information flow !

    Diego

  4. Gravatar

    Sean Hogan said on Jun 24, 2010 @ 17:01

    Great work, thanks.

  5. Gravatar

    John-David Dalton said on Jun 24, 2010 @ 19:23

    Keep up the tweets and <blog>ging.
    Your posts are always a h<it>.
    You’re doing an <out>standing job covering the IE9 preview releases :{D

  6. Gravatar

    Nikita Vasilyev said on Jun 25, 2010 @ 4:39

    var bound = (function f(x, y){ return this; }).bind({ x: 1 });
    bound + ''; // "function(){ [native code] }"

    This is really bad for debugging. This one would be much better:

    bound + ''; // "function f(x, y){ return this; }"
    
    bound2 = (function f(x, y){ return this; }).bind(null, 1);
    bound2 + ''; // "function f(y){ return this; }"
    bound2.length; // 1
  7. Gravatar

    infinte said on Jun 27, 2010 @ 22:37

    Oops, there are many issues.
    And did you post them to Microsoft Connect??

    I’ve posted an issue about asian texts to the connect and this problem solved in preview3.

    Don’t only say “THAT’S TOO BAD!”. Try to improve it. Use anything you can use.

  8. Gravatar

    Rukhsar Ahmad said on Jun 29, 2010 @ 20:33

    gr8 work!

  9. Gravatar

    Garrett said on Jun 30, 2010 @ 16:05

    I see the old IE SELECT innerHTML behavior is still there (it doesn’t work). This is a fairly well-known and acknowledged bug, though for some reason, MSDN innerHTML documentation specifies that the property is implemented for SELECT.

    The HTML 5 draft for innerHTML is quite different than IE9 implementation. HTML5 and also specifies a document.innerHTML (AFAIK nobody implements that yet).

    So IE is changing its host object methods. Given the alternatives, I can’t justify trying to feature test them through serialization; that was never a good idea. The value is arbitrary and what happens if the value changes, or, what happens if the serialization employed for one host method varies from another?

    An existence inference check using typeof can be used and where needed, a capability check can be used.

  10. Gravatar

    itsnotvalid said on Jul 13, 2010 @ 19:44

    Really surprising.

    Apparently they are finally preparing to release something standard compliant.

  11. Gravatar

    Šime Vidas said on Aug 29, 2010 @ 5:39

    Is there any info on whether strict mode will be implemented in IE9? Or FF4?

  12. Gravatar

    Garrett said on Oct 9, 2010 @ 21:28

    Host objects’ [[Class]] is far from ideal as well. IE9pre3 actually violates ES5, which says that objects implementing [[Call]] (or in other words — are callable) should have [[Class]] of “Function” — even if they are host objects. In IE9pre3, alert is a callable host object, yet it reports its [[Class]] as “Object” not “Function”. Not good.

    Where did you get that from?

  13. Gravatar

    kangax (article author) said on Oct 14, 2010 @ 8:03

    @Garrett

    Ouch. Thanks for catching that. Looks like I mixed up typeof and [[Class]] :/ I’ll fix the article.

    This reminds me of that unfortunate mixup in ES5, where host objects are disallowed to have [[Class]] of “Function” (among others), even when those host objects are represented as native Function objects (and so _must_ have a [[Class]] of “Function” :))

  14. Gravatar

    Garrett said on Oct 14, 2010 @ 13:20

    Looks like it. Funny nobody else noticed that in what — nearly four months?

    There are a few issues at hand here: IE9, [[Class]], typeof, and what a host object is.

    In IE9 beta, a host method alert is implemented as a native function. This is allowed by the specification. The [[Class]] property is "Function" and when supplied to typeof, the result is also "function". No surprises there.

    typeof alert == "function"; // true in IE9 beta
    ({}).toString.call(alert) == "[object Function]"; // true in IE9 beta.
    

    .
    That covers a “host object” implemented as a native function, but there are other “host objects” that are callable in IE9, that are not functions. For example, the collections document.images, document.all et al. The collections are not functions yet as strange as it may seem IE allows them to be called, as:

    document.images(0)
    

    ES5 typeof operator says that a callable host object must result "function".

    A host object’s [[Class]] may not be any one of "Function", "String", … et al. And by host object there, they mean “non native” object.

    Now that goes to the other problem you touched about [[Class]] property of host object. By “host object” there, the spec means “non native” object and not the definition in s 4.3.8 (more on this below).

    Since the collection objects are not Functions, the class property must not be "Function". However for the typeof operator, the callable collections still result "object", as they always have. This is an ES5 spec violation.

    Since IE9 makes its collections callable, it must report “function” from typeof operator to comply with ES5.

    Now what about “host object”? In ES5, the term “host object” is a specification screw up. It seems to go back and forth from “[any] object provided by the host environment” (4.3.8) to an implicit “non native”. Post hoc discussion between Mark Miller and Allen Wirfs-Brock on es-discuss mailing list show disagreement and misunderstandings.

    Allen asks Mark Miller what he thinks a host object is and Mark replies with:

    “Objects that are not native objects.”

    Allen correctly argues the spec prose and says that a host object may be a native object and then later realizes:

    “host object” as used in the ES5 spec. in essentially all cases means “not native object”

    And the reason we must now discuss what a host object means when discussing the specification is that the specification does not explain itself, is contradictory, and its meaning not agreed upon by its authors :-(.

    And such screw up and complexity can help to explain web developer ignorance, e.g. why nobody commented on that for four months :-(.

  15. Gravatar

    raghu said on Nov 12, 2010 @ 20:17

    Is the behaviour changed since this blog is published? Latest version of IE9 beta NFE bug seems to be back in. The following code snippet alerts the message.

    var f = function g() { return f === g; };
    if (typeof g === “function”) // “undefined”
    alert(“g() is defined”);

Trackbacks

  1. links for 2010-06-25 « burningCat said:

    [...] JScript and DOM changes in IE9 preview 3 [...]

  2. links for 2010-06-25 | Don't mind Rick said:

    [...] JScript and DOM changes in IE9 preview 3 [...]

  3. IE’s big leap forward; CSS3 selectors fully supported | Ozzmoe's Universe said:

    [...] Kangax studied the JavaScript and DOM changes and finds significant improvements. He also lists quite a few things that still have to be addressed, but those items strike me as fairly minor points, most of which are probably honest oversights. [...]

  4. Ajaxian » IE9: Big leap forward, and how we can help the Microsoft inertia said:

    [...] it isn’t just CSS that is turning green. Kangax does a fantastic job at looking at JScript and the DOM. Not only does he show the good, but also the areas that still need improvement such as: [...]

  5. IE’s big leap forward; CSS3 selectors fully supported - Programming Blog said:

    [...] Kangax studied the JavaScript and DOM changes and finds significant improvements. He also lists quite a few things that still have to be addressed, but those items strike me as fairly minor points, most of which are probably honest oversights. [...]

  6. IE9: Big leap forward, and how we can help the Microsoft inertia - Programming Blog said:

    [...] it isn’t just CSS that is turning green. Kangax does a fantastic job at looking at JScript and the DOM. Not only does he show the good, but also the areas that still need improvement such as: [...]

  7. IE9: Big leap forward, and how we can help the Microsoft momentum - Programming Blog said:

    [...] it isn’t just CSS that is turning green. Kangax does a fantastic job at looking at JScript and the DOM. Not only does he show the good, but also the areas that still need improvement such as: [...]

  8. Links LXXXIX • Peter Kröner, Webdesigner & Frontendentwickler said:

    [...] JScript and DOM changes in IE9 preview 3 – Über die Javascript- und DOM-Unterstützung im [...]

  9. JavaScript Magazine Blog for JSMag » Blog Archive » News Roundup: Boomerang, IE9, Bespin Updates said:

    [...] IE9. Kangax has updated his ES5 implementation table to reflect the new ES5 features, and has a nice blog post detailing what’s been done and what still needs work. There are certainly still a few [...]

  10. Max’ Lesestoff zum Wochenende – 26/2010 | PHP hates me - Der PHP Blog said:

    [...] what about some ssh? « MagicalTux in Japan Holy. Eine SSH2-Implementierung in Plain PHP. Perfection kills » JScript and DOM changes in IE9 preview 3 3rd preview of IE9 was released yesterday, with some amazing additions, like canvas element and an [...]

Leave a Comment

Please, don't forget to escape your input (<, > and &). Wrap code sections with <pre>

Allowed tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>