Well, there is one problemo. Quite a big problemo in fact. You see, every developer’s favourite browser (Internet Explorer), refuses to maintain the length property of a subclass created like this. I mean point blank refuses:

Most library authors would love to extend the Array object (especially for those tasty iteration methods) but shy away from doing so for fear of breaking other scripts. So nearly all (with the noteable exception of Prototype) leave Array and other built-in objects alone.

It seems to me that running library code in an iframe is the way forward. You can create global properties and functions and extend the built-in objects, all without affecting code in the main browser window. Libraries and user scripts clashing with each other might be a thing of the past.

Comments (74)

It’s going to sod up people who think that they know how many frames there are on their page because they designed the page, though. It might be worth removing the created frame from the frames array. Looks to me like you can assign to the frames array’s length after you’ve created it, so you can steal its objects and then remove it from the array. In fact, you can even assign null to frames[frames.length-1] and it still works. So the iframe maybe only needs to exist for long enough for you to steal its objects, and then it can be destroyed, which means that it doesn’t hang around to pollute the page…

@sil – I tried removing the iframe but the code choked. I think that the host environment still has to exist for the constructors to work. Maybe just removing it from the array as you suggest is the solution? Not that I think this is a very big problem compared to namespace and prototype pollution.

Maybe. I’ve only just started experimenting with running code in iframes. I was trying to solve a real-world problem with sandboxing JavaScript. After messing with iframes for a bit, a dozen light bulbs went off in my head.

Oh, this is totally brilliant!Have you tried it across a range of browsers and OSes yet to probe its portability yet? You know, this ought to work both ways — similarly, code run inside that frame should be similaryly protected from Prototype poisoning. A big hug to you, Dean! ^_^

Here I used to think all the OO magic of javascript came wrapped in one perverted form of the function object or another, and then you go showing off there’s one hidden in the cooling shadow of a frame. Amusingly beautiful!

I’d be interested in a different approach: using an iframe as an “intrinsic” namespace (similar to what’s being implemented in JS2). It’d be useful to have a “clean slate” at your disposal whenever you need it.

In order to use this, don’t you need to wait until onload to append the new iframe? That means your new Array2 won’t be available to any included libraries until the page is loaded, and any libraries wanting to use this approach all have to wait until page load to initialize. Isn’t this a problem?

Instead of an iframe, how about experimenting with IE’s XML data islands or with the Document object that is returned with XMLHttpRequest.responseXML.ownerDocument.parentWindow, which may or may not (I don’t know) return a Window object that is separate from the current one.

Andrea, the declaration of the Array2 variable is always executed before the code in a popup window. Maybe it’s by design. However, I think it’s more intuitive to put it before the call to createPopup() because it’s a bad practice to depend on any implementation specific behaviors.

I am interested in finding a way to add methods to the XML Element objects returned by XMLHTTPRequest.

I’m working on the OpenLaszlo runtime (www.openlaszlo.org), our data model is a superset of the DOM API, we have some additional methods which our data nodes support. For IE we are forced to deep copy the
entire DOM tree for a data set into a tree of our own data nodes, whereas in Firefox we can just add the new methods to the native XML node class prototype.

Interesting observation but to me this seems like a lot of potentially buggy hackery for some sugar you want but do not need. In order to get the sugar, reduce your for loops by a couple characters and also decrease performance, how much code will you need to hack around the browser bugs? When a new browser is released and the code breaks then what?

Weren’t we all happy when we could stop using iframes and could start using XMLHttpRequest objects?

you can also use new ActiveXObject(”htmlfile”);
in IE instead of an iframe (I know the popup method has been discuss for IE too). A link discussing the ActiveXObject(“htmlfile”) can be found here: http://alex.dojotoolkit.org/?p=538

Peter,
there are many useful things that can be done with IFRAMES, they where not meant to transport data, but I see you already have come to know they are good also for this…

@Dean,
you are on the right lane, this is a good use of IFRAMES, I would add that they were meant for it… They provide a level of abstraction while beeing child of the same window, they are new native ‘scope’ (that may be extended or not).

I repeat myself once more, Web Applications need IFRAMES…and this method adds another reason to use them, also a bit naif it’s better than loosing native Javascript funcionality forever.

Dean,
I can actually SCOPE different API this way without one affecting the other and using both of them in the same page/document. I have seen on jQuery docs that some tricks and modifications are needed to load jQuery and Prototype at the same time. I have them both running, and I tested adding Mootools also…

I still haven’t setup any text for it, but you may view the sources in the
JsCOPE example.

Unfortunately all these API where not designed to work this way…I should fiddle and adjust some ‘top’, ‘self’ and ‘parent’ references to window and document here and there…but most of it works…I tested it live with JShell bookmarklet.

I don’t think this will be practical for everyday use, but just in case some developer whish to have a peek at it I will post some more examples and documentation as soon as I find more time…

Tested in Mozilla/Firefox and IE, should work on Safari and Konqueror if the API are supported but only minor tests has been done on these browsers. Please report.

@Thomas/Matthew – Apologies. Your posted code does indeed work. I should follow my own advice and read and test things properly! Although your posted code works it is not a true subclass and will certainly perform pretty badly. That said, I still should have tested it before bashing it. Sorry!

As I mentioned in an email to Dean, the drawback to the method that you and I proposed is that the methods have to be added to each Array instance at the time of instantialization. In normal “subclassing” (or prototype extension) the methods only have to be added once (to the prototype) when the script is loaded.

So, like Dean implied, it’s possible that this could add quite a bit of overhead, depending on the number of methods you’re adding. However, I don’t think it’s as bad as it sounds.

I did a quick test (using FF and IE5.0) and found that creating an instance of Dean’s Array2 is approximately twice as fast in IE5 and six times as fast in FF, when 10 methods are added. (The more methods one adds, the greater the benefit of using Dean’s technique.) Of course, these numbers should be kept in context: creating 1000 XAArrays (with ten extra methods) still only takes ~187ms.

In the end, it’s up to the user to weigh the drawbacks and benefits of each method. My first reaction was to agree with Linan Wang’s comment: the solution posed here seems bigger than the problem. However, I think using an iframe in place of a vanilla object for a namespace is a great idea that shows some real promise. And if you’ve already got the iframe sitting around, why not borrow its Array prototype?

[…] A week ago Joe Walker posted a note on the insecurity of JSON. I’m using JSON for almost anything so I was shocked a bit by his findings. Sleepless nights went by and then I thought of a counter hack so one could secure his JSON again. I remembered a post by Dean Edwards (yeah, the packer guy) about subclassing Array objects. In this article I’ll present a way to take over the hacked Array object, and secure it again. […]

[…] Another nifty usage of the iframe (others are fake AJAX Uploading, subclassing the Array object, … erm, is there any other?): print only contents of a specified element. I feel a Prototype rewrite coming up Spread the word! […]

as suggests Ofir Herzas will occupy memory with the body of the method “each”. There will be as many “each” methods as are instances of the Array2. With prototype property of the constructor you have the advantage that the body of the method is in memory only once and is shared by all other objects created as instances through that constructor.

If you use an iframe to transport a native constructor this will uses its prototype as expected.

What is less expected is that if you use some native prototype method that return a new instance of the native constructor (i.e. slice) this will be an instanceof Array, and not an instanceof TransportedArray.

This means that you loose all your stuff and you have to convert each time every returned variables.

For this reason, and many others, why do not use directly an ArrayObject?

I see that the original article is quite old, so I don’t know if Dean’s opinion on using iframes as a namespace for your own library would still hold.

While this would be a perfect solution for extending the native JavaScript objects, you would have to avoid the use of ‘window’ and ‘document’ in your library code. (Something that you would always encounter when writing a ui-library and working with iframes.)

What’s happen if i iterate over Array2 instance with: for .. in The attached property and method of the Array2 is visible in loop. Just like associative arrays and just like Array.prototype.someProperty.

What is performance of this hack? If i want clean copy of Array, i need to load new JavaScript machine with clean Array.prototype and everyone else object in JavaScript.

Why the article title is “How To Subclass The JavaScript Array Object”? This is not subclass of Array Object. This is clean copy. If i have code like this:
Array2 instanceof Array //false
This break object oriented concept.

For my more clean is static member of Array. If i want each, i will make:
Array.each
No confused for me, and my reader. Array.each is more simple. Only disadvantage of this technique is allocation memory for one pointer to array object in arguments of each.

[…] big change to arrays is the ability to properly inherit from the Array type. Dean Edwards has a whole post about trying to create a subtype of Array and the problems he encountered. The biggest problem is […]

At some point several weeks ago I started thinking about building a Collections framework for JS that would mimic the feature set that we have in Java Collections. I started out with a class that used Arrays as storage repositories. I then realized that I was still leaving the door open to unintended copies of this object, getting passed around even if the core data repo was reference based. I found this tutorial and started weeks of experimentation sub-classing Array. Heres what I found,

1. A subclassed Array (obj.prototype = new Array) is many many orders of magnitude slower than obj = Array; that stands to reason.

2. so now I need to get Array as an assignment for the collection. ok… sub frame to extract for all browsers. Not Safari actually.. ok.. window to extract for all browsers.. not for FF 3.6, ok … a combination, carving out the best method for the browser at hand. Let me tell ya, I’ve never had so much frustration as I did that week. When all was said and done:

3. An object that encapsulated the array, was just as fast as the obj=Array, and much faster than prototyping Array. That was a bit supprising at first, not so much once you think about what happens when you call “this” on an object’s prototype (V8 engine is the exception). if the user wanted array functionality for direct iteration over large data sets he/she/i could get it at obj.array.

It’s an interesting idea, in the end though, It’s more trouble than its worth. That is, unless you have to have an object that has the special properties of Array. If that’s the case. obj = Array; is your best bet

[…] of screencasts about the core idea behind FuseJS. I clearly remember the Dean Edwards post that started it. Funny how the reaction to a technical musing could grow to such an impressive project. Interesting […]

Awesome. Hours of googling has made me realize you’re the one person who has ever written about this problem. I can’t believe more people haven’t run into it. Thanks for the writeup, even if it was from 4 years ago.

I know this post is old, but was hoping you could help me. Is there a way to make your code work with an already existing method? So basically I want to override the push method but still call it before doing the additional functionality I need. I made an example: http://jsbin.com/ilehu5/7/edit

Comment by: Koh

Posted: 2011/03/15 9:13 pm

Comment: #72

[…] prototype functions to get access to private variables. I have to admit that this idea came from this post from JavaScript extraordinaire, Dean Edwards. Have […]