IE "Array" Sub-classing

From RuntimeWiki

Jump to: navigation, search

Contents

Title

IE "Array" Sub-classing Problem

Detailed write-up

Description

This is an issue well articulated by reference How IE Mangles The Design Of JavaScript Libraries. He also presented a test case that everyone can try out.

The core issue is that on Internet Explorer, when you use the "Array" base class as the prototypal delegate to define your own classes, the “length” property of the user-defined class does not work. When a developer uses the built-in array methods like push, pop, and shift, these methods dutifully change the internal contents of the subclass instance’s indexed attributes, but they don’t manipulate the "length" property. This means that while you can use for (var x in list) {... style iteration, you can’t do anything aside from key iteration to know how many items are in the array.

At the recent OpenAjax F2F meeting, Bertrand Le Roy requests that people check IE8 and report a bug if it is not fixed.

Why Is This Important?

Arrays without a working "length" property are nearly useless. To get around this issue, one can try to wrap the intrinsic functions and detect how they manipulate the length property, but then you’ve ruined their [DontEnum] status and now they end up in the “iterable”surface area of instances.

As a result, toolkits like Dojo and jQuery are forced to do “giant hacks” to make this work. In Dojo, when you use the “new” keyword with the dojo.NodeList function, you expect that the system will create a new instance and do its normal “stamp with a constructor” business. Instead, Dojo resorts to creating (and populating) a regular Array instance and “NodeList-ifying” it by copying named attributes from the class prototype into the instance as member properties. The “constructor” function then explicitly return a new object, bypassing the “new” keyword’s create/stamp machinery, at which point the return of the new operator becomes our explicit return and not the object which it would have otherwise implicitly returned.

Dojo 0.9 uses an even more aggressively hackish workaround for IE which involved creating a sub-document and mapping its interpreter’s intrinsic Array class into the parent document at a different name. Both are slow for different reasons but Dojo eventually switched to the create-and-mix-in style because some popup blockers were interfering with the old method. JQuery gives up all “[]” index operations. It manually maintains its internal length property by re-implementing all of push, pop, etc. functions. This has the benefit of allowing prototypal delegation to work of pre-existing instances when new features are added to the base prototype, but at the expense of no longer being able to think about a dense list of things as an array. Dojo’s approach is painful, but so are all the alternatives today.


Background material that request this feature

Discussion

Adrian Herscu's comments

It is not explained why someone needs to inherit from the Array prototype and what are the current alternatives.

NOTE: A short coding example would be helpful.

Mike Wilson's comments

I think the text explains the case quite well; you want to create a class with additional array methods that is still an Array, but you don't want to modify the native Array class (contrary to what prototype does). You can find code examples at the top of http://dean.edwards.name/weblog/2006/11/hooray/.

An additional use-case is when you are using libraries that implement RPC-style communication and you want to map types between server and browser. Often you want to map list-like types on the server to arrays on the client, and if you want to be able to distinguish between different mapped list types then you want to augment your browser arrays with type info in some way. This can be done in several ways, but subclassing is the most elegant way as it supports the use of instanceof.

Phase I Voting - Vote for Your Top 5 Features

NOTE: PHASE I VOTING IS NOW OPEN. (2008-04-01) We have now changed the voting procedure. Instead of putting votes on each separate wiki page, we are asking people to cast their Phase I Votes on the following wiki page:


Phase II Voting

More about this later.

Personal tools