3
function test(o) {
    console.log("Object:", o);
    console.log("Assign test:", Object.assign({}, o));
    console.log("Keys test:", Object.keys(o));
    console.log("JSON test:", JSON.stringify(o));
}

var el = document.getElementById("question");                 /* or document.body */

test(el.style);                                               /* works as expected */
test(el.getBoundingClientRect());                             /* behaves like {} */
test(Object.assign(el.getBoundingClientRect(),{aaaa: 1111})); /* works... only for aaaa */

Why?

Output (test results)

See PasteBin.

MDN documentation

  1. Element.getBoundingClientRect()
  2. DOMRect
vsync
  • 118,978
  • 58
  • 307
  • 400
7vujy0f0hy
  • 8,741
  • 1
  • 28
  • 33

1 Answers1

5

Object.assign and Object.keys are working with own enumerable properties. DOMRect properties are inherited from DOMRectPrototype and cannot be accessed by those methods.

You can prove that by:

let rect = el.getBoundingClientRect();
rect.hasOwnProperty('x');                        // === false
Object.getPrototypeOf(rect).hasOwnProperty('x'); // === true

I used Lodash _.assignIn which iterates over own and inherited source properties:

https://jsfiddle.net/msazmfxo/

UPDATE

Based on this answer, 7vujy0f0hy found the acceptable solution:

var ownify = input => 
               Object.keys(Object.getPrototypeOf(input)).reduce((output,key) => 
                 Object.assign(output, {[key]: input[key]}), Object.assign({}, input));

test(ownify(el.getBoundingClientRect())); /* apparently works! */

(Although it iterates only over one level of inheritance, attributes from deeper levels will be still missing)

Community
  • 1
  • 1
phts
  • 3,889
  • 1
  • 19
  • 31
  • Very nice function, this `_.assignIn`! I wish it were native. I replaced `o.x` in your Fiddle with `o.width` which is a property coincidentally extant both in `CSSStyleDeclaration` and `DOMRect`. Also, contrary to MDN, `DOMRect` in my Chrome (Windows) lacks properties `x` and `y`. Here’s [my fork](https://jsfiddle.net/7n11vt7r/) of your Fiddle, along with some other improvements for educational value. P.S. The correct spelling is “prove” (verb), not “proof” (noun). – 7vujy0f0hy Mar 10 '17 at 09:19
  • [Even better Fiddle](https://jsfiddle.net/7L82r3b9/4/). I reverted `function test()` to the original form and instead added a fourth call: `test(_.assignIn({}, el.getBoundingClientRect())); /* just works! */` in the main code. – 7vujy0f0hy Mar 10 '17 at 09:32
  • 1
    Based on your post, I created a function `ownify()` that takes an object `input` and returns a new object `output` that _owns_ all inherited properties of the old object `input`. See [new Fiddle](https://jsfiddle.net/esheytbu/). I wish an accepted solution contained this function (if it has no flaw). Can we add it to your answer? – 7vujy0f0hy Mar 10 '17 at 10:44