IE8 Cannot add properties to JavaScript object returned by window

748 views Asked by At

I just came across this odd issue in IE8 and I cannot seem to find any more details about it. Naturally, if I create a JavaScript object, however I do it, I can simply add properties by dynamically defining them:

var rect = {};
rect.x = 200;

Great. Well in IE8 (and I'm not sure what other IE's), if I call a method like this:

var span = document.getElementById('my-span');
var rect = span.getBoundingClientRect();
rect.x = Math.round( rect.left );

then I get the IE error "Object does not support this property or method." This of course does not happen in the first case I mentioned where I personally defined my own object in javascript. Now the easiest workaround will be to do this:

var clientRect = span.getBoundingClientRect();
var rect = { top: clientRect.top, left: clientRect.left, right: clientRect.right, bottom: clientRect.bottom };
rect.x = Math.round( rect.left );

That's no problem. But what I am wondering is why won't IE8 let me dynamically add fields/properties/attributes (I am not sure of the correct JS terminology) to this object returned by the getBoundingClientRect() method? Is there another (correct) way to add properties? Does this happen for all objects returned by methods from the window object? Is this documented? Or is it a bug? (In which case I'll take the workaround and move on).

2

There are 2 answers

3
ArtOfCode On BEST ANSWER

Your problem is in the fact that the result of getBoundingClientRect() is read-only. Thus, you cannot add properties to it. You can however read them into your own object (as your workaround does). There is a slightly more succinct way to do it:

var span = document.getElementById("span");
var rect = span.getBoundingClientRect();
var myRect = {};
for(var key in rect) {
    myRect[key] = rect[key];
}

This results in myRect having all the properties of the getBoundingClientRect() result, but they are now read-write, and you can add myRect.x to them.

EDIT: FF and Chrome <= 37 appear to return getBoundingClientRect() read-write by default

0
Cool Blue On

Just to be clear, it is only an issue for IE8 and earlier as pointed out by @Teemu.

Object.getOwnPropertyDescriptor(window,'rect')
// Object { configurable=false, enumerable=true, writable=true, ...}

As a work-around, why not wrap it in an object...

    var rect = {
        clntRect: span.getBoundingClientRect(),
        x: function () { return Math.round(this.clntRect.left) },
        y: function () { return Math.round(this.clntRect.top) }
    }

or...

    var rect = {
        span: span,
        clntRect: function () { return this.span.getBoundingClientRect() },
        x: function () { return Math.round(this.clntRect().left) },
        y: function () { return Math.round(this.clntRect().top) }
    }