Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why isn't it possible to delete Javascript variables automatically generated from the DOM?

It may not be common knowledge, but "Javascript on many (all?) modern browsers seems to create variables on the window object for DOM elements with IDs".

Knowing this I'd like to be able to delete these variables and below is some code I've tried without success. Also consider my screenshot of console.log statements, which first indicates why as not being a property of window (it should come in between "webkitUrl" and "window"), but nevertheless in the two console.log statements that immediately follow the first, window/why is shown as the div from the document?

Why can't these automatically generated variables be deleted from their parent object, just like any other?

<!DOCTYPE html>

<html>
<head>
    <script>
    setTimeout(function() { //poor man's document/ready
        var allElements = document.getElementsByTagName("*"), elementId;

        for (var i=allElements.length; i--; ) {
            elementId = allElements[i].id;

            if (elementId && window[elementId] instanceof HTMLElement) {
                delete window.why;
                console.log(window);
                console.log(window.why);
                console.log(why);
            }
        }
    });
    </script>
</head>

<body>
<div id="why"></div>
</body>

</html>

enter image description here

like image 680
Dexygen Avatar asked Jul 05 '16 17:07

Dexygen


1 Answers

That's because these properties are not directly stored in window. Instead, it behaves like a proxy.

For example, see what Firefox does when you use getOwnPropertyDescriptor on WindowProperties (from which window inherits):

bool WindowNamedPropertiesHandler::getOwnPropDescriptor(
  JSContext* aCx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId,
  bool /* unused */, JS::MutableHandle<JS::PropertyDescriptor> aDesc
) const {
  // ...
  Element* element = document->GetElementById(str);
  if (element) {
    JS::Rooted<JS::Value> v(aCx);
    if (!WrapObject(aCx, element, &v)) {
      return false;
    }
    FillPropertyDescriptor(aDesc, aProxy, 0, v);
    return true;
  }
  // ...
}

You might think that when you set an ID to some element, Firefox stores it as a global property. But it doesn't work like this: it's when you attempt to access the property that Firefox will use GetElementById to know if there is some element with that ID or not, and answer accordingly.

Even more, deletions are explicitly forbidden:

bool WindowNamedPropertiesHandler::delete_(
  JSContext* aCx, JS::Handle<JSObject*> aProxy,
  JS::Handle<jsid> aId, JS::ObjectOpResult &aResult
) const {
  return aResult.failCantDeleteWindowNamedProperty();
}

This behavior is hard-coded and you can't prevent it. So if these properties annoy you, just override them by declaring your own variables.

like image 181
Oriol Avatar answered Sep 21 '22 01:09

Oriol