从 JS 中的 ids 自动创建变量? [复制]
Posted
技术标签:
【中文标题】从 JS 中的 ids 自动创建变量? [复制]【英文标题】:Automatically created variables from ids in JS? [duplicate] 【发布时间】:2011-10-30 04:58:03 【问题描述】:就在今天,在进行了几年的 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)可以立即执行此操作。
【问题讨论】:
嗯...您在哪个浏览器和版本中看到这个?我在 FF 3.6 中,在 Firebug 中的box
上收到未定义的对象错误。不用说,我确信这是不符合 ECMA 的行为。
@65Fbef05 是的,FF 似乎只在怪癖模式下支持这个。我在 IE6+ 和 Chrome 中测试过
我对您的问题没有正确答案,但我非常担心您的对象box
是在document
范围之外创建的。就我而言,这不是一个怪癖。这是一个错误。
为什么要禁用它?因为内存泄漏或不可预知的错误?
@sangdol 确实存在不可预测的错误
【参考方案1】:
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 strict。
JavaScript 有许多特性,让初学者和新手更容易使用,我怀疑这是这样的特性之一。如果您是专业人士并且想要高质量的代码,请使用 "use strict";
并始终使用 JSLint 您的代码。 如果您使用这些指南,则此功能绝对不会打扰您。
这里是 a useful video about ES5 由 YUI 剧院提供(虽然它已经 2 岁了,但目前仍然相关,因为还没有 ES6)。
【讨论】:
严格模式与此无关。 5 年后它仍然存在 6 年后,它仍然存在! 7 年后,它仍然存在! 8 年后,它仍然存在!【参考方案2】:这是我能够想出的方法,用于删除为具有 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 对象时,该全局变量设置为未定义。事实证明,浏览器也会为某些类型的带有名称属性的标签(如表单元素)执行相同的自动全局设置,因此我们也将其清除。
当然,这段代码不知道你自己的代码是否创建了一个与 id 同名的全局变量,所以显然最好不要在你自己的代码中这样做,或者在你的全局变量之前调用这个函数已初始化。
不幸的是,您不能在 javascript 中删除全局变量,因此将其设置为 undefined 是最好的办法。
仅供参考,我尝试以另一种方式执行此操作,您枚举全局变量以查找作为 HTMLElement 实例且名称与它们指向的元素的 id 匹配的变量,但我找不到枚举全局变量的可靠方法。在 Chrome 中,您无法在 window 对象上枚举它们,即使您可以通过 window 对象访问它们。所以,我不得不反其道而行之,获取所有带有 id 的 DOM 对象并寻找与之匹配的全局变量。
仅供参考,您在问题中询问了严格模式。严格模式仅适用于给定的代码范围,因此不会有任何方法使其影响全局命名空间的设置方式。要影响这样的事情,它必须是在文档被解析之前的文档级别的东西,比如 DOCTYPE 选项或类似的东西。
有关此功能的注意事项。
-
在您创建任何自己的全局变量之前运行它,或者不要创建任何您自己的全局变量,其名称与指向该 DOM 对象的 ID 或名称属性相同。
这是一次性的,不是连续的。如果您动态创建新的 DOM 对象,则必须重新运行此函数以清除可能从新 DOM 对象生成的任何新全局变量。
全局变量设置为未定义,这与它们一开始就不存在的情况略有不同。我想不出一个真正重要的编程案例,但它并不相同。很遗憾,您无法删除全局变量。
【讨论】:
这很痛苦,幸运的是你不需要这样做。只要确保你总是声明你的变量。使用 JSLint。【参考方案3】:这里的问题是全局作用域中有浏览器在运行时定义的对象,并且您希望防止这些定义干扰您的代码。我不知道有什么方法可以关闭这种行为,但我确实有两种解决方法:
1) 正如您链接到的文章中所建议的那样,您可以通过确保在使用每个变量之前定义它来解决此问题。我将通过JSLint 运行我的代码来实现这一点,它会警告这类事情(除了一堆其他常见错误)。
2) 但是,由于可能会忘记通过 JSLint 运行代码,因此您可能更喜欢工具链中无法忘记的步骤。在这种情况下,请查看CoffeeScript - 它是一种与您在使用前编译成 javascript 的 javascript 非常相似的语言,它会为您插入正确的 var
定义。事实上,我怀疑您无法编写依赖于使用 CoffeeScript 自动创建元素变量的代码。
【讨论】:
我已经向我的 SVN 服务器添加了一个提交后挂钩,它将使用 JSLint 验证所有.js
文件。非常有用。【参考方案4】:
我认为没有办法禁用它,但你不需要太重视它。如果你害怕不可预知的错误,你可以使用JSHint 或JSLint 来避免它们。他们将帮助您避免错误。例如,如果您使用未声明的变量,它们会警告您。
【讨论】:
【参考方案5】:是的,大多数浏览器都会这样做,但就像你说的那样,有些浏览器不会(firefox)所以不要指望它。在 js 中覆盖这些变量也很容易,我可以想象 container
之类的东西可能会被使用该变量的人直接覆盖,而无需先声明它。
没有办法在 chrome afaik 中将其关闭,但即便如此,要解决这个问题并为所有浏览器修复它可能会很麻烦。
不要太重视它,但要小心。这就是为什么要避开变量的全局作用域的原因之一。
为了完整起见,这些浏览器肯定会默认这样做:Chrome、IE9 & compat、Opera
更新:ECMAScript 的未来版本可能包含某种选项,因为正在进行讨论,但这不会解决旧浏览器中的“问题”。
【讨论】:
四年过去了,但无论如何,现代 Firefox确实 做到了这一点。我很惊讶(也很震惊)发现我们网站中有相当多的代码块,在多个页面上使用,依赖,但我们还没有任何关于它的错误报告。因此,它似乎是可靠的——无论如何,就目前而言。当然,我的团队中并不是只有我一个人对这一发现感到恐惧,而且我们肯定会在下一次机会时对其进行重构,因为我们也不相信它,而是相信它的价值。 【参考方案6】:我认为这没什么大不了的。尤其是对于我们这些考虑全局命名空间污染和冲突的人来说,这似乎很混乱,但实际上它并没有真正造成问题。
如果您声明自己的全局变量,它只会覆盖浏览器为您创建的任何内容,因此不会有任何冲突。我唯一能看到它可能导致问题的地方是,如果您正在测试是否存在全局声明,并且基于对象 ID 的“自动”全局会妨碍您并让您感到困惑。
在实践中,我从未认为这是一个问题。但是,我同意这似乎是他们应该摆脱或让你关闭的东西。
【讨论】:
以上是关于从 JS 中的 ids 自动创建变量? [复制]的主要内容,如果未能解决你的问题,请参考以下文章