What is the reason behind Object.hasOwn(x,y) being different from Reflect.ownKeys(x).includes(y) when x represents a CSSStyleDeclaration object and y is a hyphenated property such as 'z-index'?

Both of these conditions are true:

'z-index' in getComputedStyle(document.body) // true
Reflect.has(getComputedStyle(document.body), 'z-index')  // true

Additionally, the following statements also evaluate to true, indicating that 'z-index' is an own property of the CSSStyleDeclaration object:

getComputedStyle(document.body).hasOwnProperty('z-index')  // true
Object.hasOwn(getComputedStyle(document.body), 'z-index')  // true

However, this statement evaluates to false:

Reflect.ownKeys(getComputedStyle(document.body)).includes('z-index')  // false

How can Object.hasOwn(x, y) be true, while Reflect.ownKeys(x).includes(y) is false? It doesn't seem logical.

It's worth noting that even though getComputedStyle(document.body) returns a read-only computed CSSStyleDeclaration object, the same issue arises with an HTMLElement's style property:

Object.hasOwn(document.body.style, 'z-index') // true
Reflect.ownKeys(document.body.style).includes('z-index') // false

According to MDN (https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle)

CSS property values may be accessed using the getPropertyValue(propName) API or by indexing directly into the object such as obj['z-index'] or obj.zIndex.

The convenience of accessing the value by obj['z-index'] is understood. The confusion lies in the discrepancy between Object.hasOwn(x,y) and Reflect.ownKeys(x).includes(y) under Ecmascript rules.

Edit: A related question on StackOverflow was found (how does it work element.style["background-color"]) but remained unanswered.

Answer №1

Your analysis of the situation is spot-on.

There are no restrictions preventing you from creating such a scenario yourself using a Proxy. Here's an example:

function createCaseInsensitiveObject() {
  return new Proxy({}, {
    getOwnPropertyDescriptor (target, property) {
      return Reflect.getOwnPropertyDescriptor(target, property.toLowerCase())
    },

    defineProperty (target, property, descriptor) {
      return Reflect.defineProperty(target, property.toLowerCase(), descriptor)
    },

    has (target, property) {
      return Reflect.has(target, property.toLowerCase())
    },

    get (target, property) {
      return Reflect.get(target, property.toLowerCase())
    },

    set (target, property, value) {
      return Reflect.set(target, property.toLowerCase(), value)
    },

    deleteProperty (target, property) {
      return Reflect.deleteProperty(target, property.toLowerCase())
    }
    
    // Note: ownKeys is NOT overridden as it
    // would be impractical to return all permutations
    // of casing like hElLo etc.
  })
}

const obj = createCaseInsensitiveObject()
obj.Hello = 123
console.log(obj.HELLO) // 123
console.log(obj.hElLo) // 123
console.log('hElLo' in obj) // true
console.log(Reflect.ownKeys(obj)) // ['hello']
console.log(Reflect.ownKeys(obj).includes('hElLo')) // false

This demonstrates why there may be discrepancies: while the [[Has]] internal method returns true and the [[GetOwnProperty]] internal method returns a valid descriptor, the [[OwnPropertyKeys]] internal method may not contain that key in the returned array.

The [[OwnPropertyKeys]] internal function should not be used simply to check if a known key exists; instead, it should be iterated over to discover keys. In practice, you would use Object.hasOwn to check for a specific property's existence, and utilize Object.keys (or Object.getOwnPropertyNames) for iterating over properties. This way, the CSSStyleDeclaration will behave consistently by returning each real property only once, accepting both forms when accessing a property directly.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Modifying the appearance of a WordPress website with CSS styling

I am currently using WordPress and I am excited about making changes to the CSS style sheet. After visiting , I realized that there is no option for editing the 'CSS' under Appearance → Customize → 'CSS'. My usual process is going ...

Running javascript code after the completion of the render method in Reactjs

I am working with a ReactJS component: const com1 = React.createClass({ render: function() { return ( <a href='#'>This is a text</a> ); } }); I am looking to run some Javascript/jQuery code once the rendering ...

The appearance of the page varies when viewed on different computers using the same version of Firefox

Previously, I posed a question with a touch of irony regarding Firefox without providing an example. As a result, my question was downvoted and I had to request its removal. Now, I have an example illustrating the issue at hand. It took some time to clean ...

"Filtering a JSON File Based on Button Data Attributes: A Step-by-

I am working with a set of buttons that have specific data-map attributes as shown below: <button class="btn btn-default mapper" data-map="2015-11-13">Monday</button> <button class="btn btn-default mapper" data-map="2015-11-14">Tuesday&l ...

Prevent divs from jumping to a new line with the float property

I've been busy working on a responsive webpage and so far, everything is going smoothly. The only issue I'm facing is that when the browser window size decreases and reaches a certain point, the div elements jump to the next line. Take a look at ...

Ways to determine if the property of a document has been altered?

Currently, I am in the process of writing tests for an Express CRUD application. The specific route I am focused on is the account recovery route. This route accepts POST requests with an email included in the body. Essentially, the application will search ...

Step by step guide to creating individual counter sections

I have set up a counter section where the numbers go from 0 to a specific value. However, currently all three counters start counting simultaneously. Is there a way for the first counter to count up first, then once it's done, move on to the second c ...

Using regex, match any word along with the preserved white space and consider parentheses as a single word

I need help with creating a regex pattern to split a string of words in a specific way. The current pattern I've been using is (?!\(.*)\s(?![^(]*?\)), but it's not giving me the desired outcome. It's close, but not quite the ...

Identical Identifiers in jQuery Tab Elements

Currently, I am utilizing the jQuery Tabs library within a small application. Within this page, there are 5 tabs that load content using Ajax. However, an issue arises when a tab is loaded and remains in the browser's memory along with its HTML elemen ...

Checkbox enabled Bootstrap image

I am encountering a minor issue where I am attempting to incorporate a simple image that can be toggled on and off by clicking on it. After coming across some bootstrap code online, I decided to test it in my project. Unfortunately, the code does not seem ...

Go to a different webpage containing HTML and update the image source on that particular page

I am facing an issue with my html page which contains multiple links to another page. I need to dynamically change the image references on the landing page based on the link the user clicks. The challenge here is that the link is inside an iframe and trigg ...

``There seems to be an issue with the alignment of items in the

I am fairly new to using css and bootstrap and I am currently working on integrating a carousel into my angular web app. I copied the code from the bootstrap site but I am facing challenges in aligning everything properly. Additionally, the image slides do ...

Enhance your HTML5 video by incorporating strategically placed buttons (images) as an overlay

Recently, I embedded a video: <video preload muted autoplay loop id="sty"> <source src="content/1/sty.mp4" type="video/mp4"> </video> To make this video full-width, I made sure to set the CSS properti ...

Numerous toggles available for the mobile version

Hey there, I need some help! I have a footer navigation on my desktop website with 3 Ul elements. I want to turn each Ul into a toggle for the mobile version. Can anyone assist me with this? Thanks in advance! <footer class="footer"> <d ...

Need help with TypeScript syntax for concatenating strings?

Can you explain the functionality of this TypeScript syntax? export interface Config { readonly name: string readonly buildPath: (data?: Data) => string readonly group: string } export interface Data { id: number account: string group: 'a&a ...

Passing references between multiple components

I'm currently working on an application using Material-UI in conjunction with styled-components. I am faced with the challenge of passing a ref down to the root <button> node that is created by Material-UI. Material-UI provides a buttonRef prop ...

Ways to resolve - Error: Unable to access 'comments' property of null

I am currently working on developing a blog web application and I am facing an issue with enabling user comments on posts. Despite extensive research and attempts to troubleshoot by searching online, I have not been able to find a solution. I have been str ...

Why is my custom function failing to operate on an array?

My function is created to organize and remove duplicates from a provided array. Below is an excerpt of the code: Bubble Sort - function organize(postsCollection, type, direction){ let target = postsCollection[0][type]; let swapp = false, ...

What is the best way to customize Node.js configuration when it is executed through npm?

Check out this documentation on node config: node myapp.js --NODE_CONFIG='{"Customer":{"dbConfig":{"host":"customerdb.prod"}}}' However, if I run a npm script, all parameters will be passed to npm instead of nodejs, right? How can I pass the -- ...

Answer for background picture when reducing magnification

Currently, I am facing the challenge of converting a PSD template to HTML. Specifically, I need guidance on how to handle the background food images (highlighted in red in the image) when zooming out the browser. The total width is 1300px with a container ...