【问题标题】:Why isn't it possible to delete Javascript variables automatically generated from the DOM?为什么不能删除从 DOM 自动生成的 Javascript 变量?
【发布时间】:2016-11-07 15:51:08
【问题描述】:

这可能不是常识,而是"Javascript on many (all?) modern browsers seems to create variables on the window object for DOM elements with IDs"

知道了这一点,我希望能够删除这些变量,下面是一些我尝试过但没有成功的代码。还要考虑我的 console.log 语句的屏幕截图,它首先表明 why 不是 window 的属性(它应该位于“webkitUrl”和“window”之间),但是在紧随其后的两个 console.log 语句中第一个,窗口/为什么显示为文档中的 div?

为什么这些自动生成的变量不能像其他任何变量一样从它们的父对象中删除?

<!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>

【问题讨论】:

  • 1) 你为什么要这样做? 2)non-configurable属性无法删除。
  • delete 仅适用于“自己的”属性,而不适用于继承的属性。这些元素可能位于原型链的更下游。
  • 有趣的是,在 Firefox 中,Object.getPrototypeOf(Object.getPrototypeOf(window)).hasOwnProperty("foobar")true.getOwnPropertyDescriptor() 将其列为 configurablewritable,但我无法删除或写入它。
  • @squint 有趣的是,在我在 Chrome 中的测试中,它确实删除了它(返回 true),但之后仍然存在。 JSFiddle Demo
  • @squint 完全正确,之后它仍然存在。对于其他所有人,我认为这会导致严格模式出现问题,不知道是否分配了 why,但如果您尝试分配原因,它确实会抱怨

标签: javascript dom javascript-objects


【解决方案1】:

这是因为这些属性没有直接存储在window 中。相反,它的行为类似于代理。

例如,当您在WindowProperties 上使用getOwnPropertyDescriptor 时,请参阅what Firefox doeswindow 继承自该window):

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;
  }
  // ...
}

您可能会认为,当您为某个元素设置 ID 时,Firefox 会将其存储为全局属性。但它不是这样工作的:当您尝试访问属性时,Firefox 将使用 GetElementById 来了解是否存在具有该 ID 的元素,并做出相应的回答。

更重要的是,deletions 被明确禁止:

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

这种行为是硬编码的,您无法阻止它。因此,如果这些属性让您感到厌烦,只需通过声明您自己的变量来覆盖它们。

【讨论】:

    【解决方案2】:

    我希望能够删除这些变量

    绝对没有理由这样做。这些全局变量are there for backwards compatibility 和浏览器几乎不会删除它们。但是,它们的创建方式使您可以简单地忽略它们 - 它们不会干扰您的任何变量。

    只需在您的脚本中声明var why;,对该元素的引用就会消失。

    为什么不能从它们的父对象中删除这些自动生成的变量?

    首先,变量一般不能删除。只有对象属性可以——只是一些全局变量是全局对象的可删除属性。

    元素引用可能无法删除,因为 a) 它们不是真正的属性,而是代理 b) 它们不是全局对象本身的属性,而是其原型的属性,或者 c) 它们是全局范围内的额外变量记录。把它们当成魔法就行了,别管了。

    【讨论】:

    • 变量(如果没有在任何地方引用)应该被垃圾收集。没有?
    • @Tuvia:当它们是全球性的时候不会,因为你永远不知道它们什么时候会被引用。
    猜你喜欢
    • 1970-01-01
    • 2015-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-14
    • 1970-01-01
    • 1970-01-01
    • 2011-03-29
    相关资源
    最近更新 更多