从JS中的ids自动创建变量?

时间:2011-08-18 22:33:26

标签: javascript

就在今天经过几年的javascript编程后,我遇到了令我吃惊的东西。浏览器为每个具有id的元素创建对象。对象的名称将与id匹配。

所以如果你有:

<div id ="box"></div>

你可以这样做:

alert(box); //[object HTMLDivElement]

首先不为该变量分配任何内容。 See the demo

出于某种原因,这似乎是in the standards,即使它可能会破坏some cases中的代码。有open bug来结束这种行为,但我现在更感兴趣摆脱它。

你们知道是否有办法禁用此功能(strict mode可能)?我是否过分重视?因为这看起来确实是一个坏主意。 (它是由IE引入给你一个提示)。

更新:似乎FF只在怪癖模式下执行此操作。其他浏览器,如IE6 +和Chrome,就可以随时使用。

6 个答案:

答案 0 :(得分:10)

ECMAScript 5 strict应该为您cannot use undeclared variables提供帮助。我不确定哪些浏览器目前支持严格模式,但我知道Firefox 4可以。

您链接的HTML规范提及a proposal to reduce pollution of the global scope by limiting this behavior to quirks-only

我不知道这个功能是否在原始规范中,但我确实希望在后续版本的ECMAScript中将其删除,禁止或以其他方式无效。 ES6将基于ES5严格。

JavaScript有许多功能,使初学者和初学者更容易使用,我怀疑这是一个这样的功能。如果您是专业人士并希望使用质量代码,请使用"use strict";并始终JSLint使用您的代码。 如果您使用这些指南,则功能不应该打扰您。

这是a useful video about ES5 YUI Theatre的礼貌(虽然它已经有2年了,但目前仍然没有相关的ES6)。

答案 1 :(得分:6)

我认为这不是什么大问题。对我们这些考虑全球命名空间污染和冲突的人来说,这似乎很麻烦,但在实践中它并没有真正引起问题。

如果您声明自己的全局变量,它将覆盖浏览器为您创建的任何内容,因此实际上没有任何冲突。唯一可以看到它可能导致问题的地方是,如果您正在测试是否存在全局声明,并且基于对象ID而导致的“自动”全局,并且会让您感到困惑。

在实践中,我从未见过这是一个问题。但是,我同意它似乎应该摆脱或允许你关闭。

答案 2 :(得分:3)

是的,大多数浏览器会这样做,但是再次像你说的那样(firefox),所以不要指望它。在js中覆盖这些变量也很容易,我可以想象container之类的东西可能会被使用该变量的人覆盖,而不会先声明它。

没有办法在chrome afaik中解决这个问题,但即使这样,想出这个并为所有浏览器修复它也可能是一件麻烦事。

不要过于重视,但要注意它。这就是为什么要逃避变量的全局范围的原因之一。

为了完成,这些浏览器默认情况下默认执行:Chrome,IE9&amp; compat,Opera

更新:ECMAScript的未来版本可能包含某种选项,因为是讨论正在进行,但这不会解决旧浏览器中的“问题”。

答案 3 :(得分:2)

我认为没有办法禁用它,但你不需要太过重视它。如果您害怕出现不可预测的错误,可以使用JSHintJSLint来避免这些错误。他们会帮助你避免错误。例如,如果您使用未声明的变量,他们会发出警告。

答案 4 :(得分:2)

这里的问题是全局范围在浏览器运行时在其中定义了对象,并且您希望防止这些定义干扰您的代码。我不知道如何关闭这种行为,但我确实有两种解决方法:

1)正如您链接的文章所述,您可以通过确保在使用之前定义每个变量来解决此问题。我会通过JSLint运行我的代码来实现这一点,CoffeeScript会警告这类事情(除了一堆其他常见错误之外)。

2)但是,由于可能忘记通过JSLint运行代码,您可能更喜欢工具链中的一个您不能忘记的步骤。在这种情况下,请查看{{3}} - 它是一个非常类似于javascript的语言,您在使用前编译为javascript,它将为您插入正确的var定义。事实上,我怀疑你不能编写依赖于使用CoffeeScript创建自动元素变量的代码。

答案 5 :(得分:0)

这是我能够想出的用于移除为ID对象自动为DOM对象创建的全局变量:

function clearElementGlobals() {
    function clearItem(iden, item) {
        if (iden && window[iden] && (window[iden] === item)) {
            window[iden] = undefined;
        }
    }

    var list = document.getElementsByTagName("*");
    for (var i = 0, len = list.length; i < len; i++) {
        var item = list[i];
        clearItem(item.id, item);
        clearItem(item.name, item);
    }
}

这将获取页面中所有对象的列表。它循环查找具有id值的值,当存在​​id值并且存在全局变量且该全局变量指向该DOM对象时,该全局变量设置为undefined。事实证明,对于某些类型的带有name属性的标签(如表单元素),浏览器也会执行相同的自动全局操作,因此我们也清除了这些。

当然,这段代码无法知道您自己的代码是否创建了一个与id同名的全局变量,所以显然最好不要在自己的代码中执行此操作,或者在全局变量之前调用此函数已初始化。

不幸的是,你无法在javascript中删除全局变量,因此将其设置为undefined是最好的。

仅供参考,我尝试以另一种方式执行此操作,您枚举全局变量,查找作为HTMLElement实例的变量,并且其名称与其指向的元素的id相匹配,但我找不到枚举全局变量的可靠方法。在Chrome中,即使您可以通过窗口对象访问它们,也无法在窗口对象上枚举它们。因此,我必须通过获取具有id的所有DOM对象并寻找与它们匹配的全局变量来反过来。

仅供参考,您在问题中询问过严格模式。严格模式仅适用于给定的代码范围,因此不会有任何方法导致它影响全局命名空间的设置方式。为了影响这样的事情,在解析文档之前,它必须是文档级别的东西,如DOCTYPE选项或类似的东西。

具有此功能的警告。

  1. 在创建任何自己的全局变量之前运行它,或者不创建任何自己的全局变量,其名称与同样指向该DOM对象的ID或name属性相同。
  2. 这是一次性拍摄,而不是连续拍摄。如果动态创建新的DOM对象,则必须重新运行此函数以清除可能由新DOM对象生成的任何新全局变量。
  3. 全局变量设置为undefined,与首先不存在的变量略有不同。我想不出一个真正重要的编程案例,但它并不相同。不幸的是,你无法删除全局变量。