3

This is true at least in Chrome and Firefox:

Object.keys(getComputedStyle(document.body)).includes("backgroundColor")  // => true
Object.keys(getComputedStyle(document.body)).includes("background-color") // => false

yet,

getComputedStyle(document.body)["background-color"]    // "rgb(255, 255, 255)"
getComputedStyle(document.body)["backgroundColor"]     // "rgb(255, 255, 255)"

So if background-color is not a key, how can

getComputedStyle(document.body)["background-color"]

show something? I know in jQuery, fontSize is the same as font-size, etc, but if it is property value access it is against the rule of how to access the property value of an object. Can any JS object behave like this?

nonopolarity
  • 146,324
  • 131
  • 460
  • 740

1 Answers1

1

There’s no magic necessary to see that behaviour alone: Object.keys only returns own, enumerable, string-named properties. Any JS object can behave like that by having "background-color" either be

  1. higher on the prototype chain, or
  2. non-enumerable.

The former is true of "background-color" on current Firefox, where it’s a getter/setter pair on the prototype of the computed style:

console.log("background-color" in getComputedStyle(document.body));
console.log(
    Object.getOwnPropertyDescriptor(CSS2Properties.prototype, "background-color"));

Chrome seems to use magic, where hyphenated aliases are enumerable properties that aren’t enumerated.

for (let prop in document.body.style) {
  if (prop === "background-color") {
    console.log("found it");
  }
}

console.log(Object.getOwnPropertyDescriptor(document.body.style, "background-color"));

Non-host objects – proxies, specifically – can still behave like that, though.

const magic = new Proxy({
  "background-color": "red",
}, {
  ownKeys(target) {
    return [];
  },
});

console.log(Object.keys(magic));
console.log(Object.getOwnPropertyDescriptor(magic, "background-color"));
Ry-
  • 218,210
  • 55
  • 464
  • 476
  • if I do `obj = getComputedStyle(document.body)` and keep on showing `obj.__proto__` and `obj.__proto__.__proto__` I don't see such a property named `background-color` either – nonopolarity Jan 07 '20 at 06:43
  • 1
    Yet `Object.getOwnPropertyDescriptor(window.getComputedStyle(document.body), "background-color")` results in `{value: "rgb(255, 255, 255)", writable: true, enumerable: true, configurable: true}` and `window.getComputedStyle(document.body).hasOwnProperty('background-color')` -> `true`. Either I'm missing something, or the browser is lying – CertainPerformance Jan 07 '20 at 06:43
  • @Ry- `Object.keys(obj.__proto__).includes("background-color") // => false` – nonopolarity Jan 07 '20 at 06:46
  • @CertainPerformance: Hm, it might be magic on Chrome. Not on Firefox. – Ry- Jan 07 '20 at 06:46
  • `Object.keys(obj.__proto__).includes("background-color")` is actually true on Firefox and false on Chrome... it is "Getter & Setter" on Firefox... not values. It'd be a surprise if the value is on the prototype, because that's supposedly shared by all objects created by that constructor function – nonopolarity Jan 07 '20 at 06:55
  • the getter and setter on Firefox is just like an alias then? – nonopolarity Jan 07 '20 at 07:01
  • @nopole: Yes.︁︁ – Ry- Jan 07 '20 at 07:02
  • CSS2Properties, by the way, is a DOM Level 2 Style thing. CSSStyleDeclaration is the modern version. The relevant part of the current draft might be at https://drafts.csswg.org/cssom-1/#dom-cssstyledeclaration-camel-cased-attribute, but I don’t know where enumeration is specified, if it is. – Ry- Jan 07 '20 at 07:09
  • 1
    [Relevant discussion](https://github.com/w3c/csswg-drafts/issues/1089) (only FF has it per specs) – Kaiido Jan 07 '20 at 07:57