javascript 为什么JS函数名和元素ID冲突?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9158238/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why JS function name conflicts with element ID?
提问by Oleg Mikheev
I've got two almost identical simple JS fiddles calling a function on select change. Function name is the same as select ID in both cases, but for some reason the first fiddle works just fine, and the second one fails with a JavaScript error is not a function
:
我有两个几乎相同的简单 JS 小提琴,在选择更改时调用函数。在这两种情况下,函数名称都与 select ID 相同,但由于某种原因,第一个小提琴工作正常,第二个失败并出现 JavaScript 错误is not a function
:
http://jsfiddle.net/AZkfy/7/- works fine in FF9 (Linux), Chromium 16 (Linux), IE8 (Windows):
http://jsfiddle.net/AZkfy/7/- 在 FF9 (Linux)、Chromium 16 (Linux)、IE8 (Windows) 中工作正常:
<script>
function border(border) { alert(border); }
</script>
<select id='border' name='border' onchange='border(this.value)'>
<option value='foo'>foo</option>
<option value='bar'>bar</option>
</select>
and
和
http://jsfiddle.net/cYVzk/- fails in FF9 (Linux), Chromium 16 (Linux), IE8 (Windows):
http://jsfiddle.net/cYVzk/- 在 FF9 (Linux)、Chromium 16 (Linux)、IE8 (Windows) 中失败:
<script>
function border(border) { alert(border); }
</script>
<form>
<select id='border' name='border' onchange='border(this.value)'>
<option value='foo'>foo</option>
<option value='bar'>bar</option>
</select>
</form>
Firstof all I fail to understand why the first one works fine, and the second one fails.
首先,我不明白为什么第一个工作正常,而第二个失败。
Second- are there any JS specifications or restrictions regarding the conflicting JS function names and element ID?
其次- 是否有关于冲突的 JS 函数名称和元素 ID 的任何 JS 规范或限制?
回答by PointedEars
This is a legacy scope chain issue originating from JavaScript 1.0 to 1.3 when there was no distinction between the programming language and what we now call a DOM API ("Dynamic HTML" back then).
这是一个遗留范围链问题,起源于 JavaScript 1.0 到 1.3,当时编程语言和我们现在称之为 DOM API(当时的“动态 HTML”)之间没有区别。
If your form control (here: a select
element) is part of a form (descendant of a form
element), then the Form
object that represents the form
element is third-next in the scope chain of code in the control's event-handler attribute values (second-next is the form control object itself, next is the Variable Object of that code).
如果您的表单控件(此处:select
元素)是表单的一部分(form
元素的后代),则Form
表示该form
元素的对象在控件的事件处理程序属性值(第二个-下一个是表单控件对象本身,下一个是该代码的变量对象)。
JavaScript? was designed by Brendan Eich (then at Netscape) as a programming language that is easy to use for beginners and that works well with HTML documents (as complement to Sun's Java; hence the ever-confusing name). Because in those early days language and (Netscape) DOM API were one, this (over)simplification applied to the DOM API as well: A Form
object has the names of the controls contained in the form that it represents as the names of its properties that refer to the corresponding form control objects. IOW, you can write
JavaScript?由 Brendan Eich(当时在 Netscape 工作)设计为一种易于初学者使用的编程语言,并且可以很好地处理 HTML 文档(作为 Sun 的 Java 的补充;因此名称一直令人困惑)。因为在早期语言和 (Netscape) DOM API 是一回事,这种(过度)简化也适用于 DOM API:一个Form
对象具有包含在表单中的控件名称,它表示为它的属性名称参考对应的表单控件对象。IOW,你可以写
myForm.border
which is the proprietary shorthand of the standards-compliant (W3C DOM Level 2 HTML), but equally backwards-compatible
这是符合标准(W3C DOM Level 2 HTML)的专有简写,但同样向后兼容
document.forms["myForm"].elements["border"]
Now, if you use a form control's name in an event-handler attribute value of a form control in a form, like
现在,如果你在一个窗体控件的事件处理程序的属性值使用窗体控件的名称的形式,像
<form …>
<… name="border" onchange='border(this.value)' …>
</form>
that is the same as if you had written the half-proprietary
这就像你写了半专有
<form …>
<… name="border" onchange='this.form.border(this.value)' …>
</form>
or the standards-compliant
或符合标准
<form …>
<… name="border" onchange='this.form.elements["border"](this.value)' …>
</form>
because a potential global border()
function is a property of the ECMAScriptGlobal Object which comes last, afterthe Form
object (an object implementing the HTMLFormElement
interface in the W3C DOM), in the scope chain.
因为一个潜在的全球border()
功能是的属性的ECMAScript其去年来的时候,全局对象之后的Form
对象(实施对象HTMLFormElement
在W3C DOM接口),作用域链。
However, the form control object referred here by border
is not callable (does not implement the ECMAScript-internal [[Call]]
method or implements it so that it throws an exception when called). So if you try to call the object with border(this.value)
, a TypeError
exception is thrown, which you should see in the script consoles (like "TypeError: border is not a function" in the Developer Tools of Chromium 16.0.912.77 [Developer Build 118311 Linux]).
但是,这里引用的表单控件对象border
是不可调用的(没有实现 ECMAScript 内部的[[Call]]
方法或实现它以便在调用时抛出异常)。因此,如果您尝试使用 调用对象border(this.value)
,TypeError
则会引发异常,您应该在脚本控制台中看到该异常(例如 Chromium 16.0.912.77 [Developer Build 118311 Linux] 的开发人员工具中的“TypeError: border is not a function”) .
Microsoft, Netscape's competitor in the 1990s, had to copy that feature for the MSHTML DOMso that code written for Netscape would also run in Internet Explorer (3.0), with JScript(1.0). And Microsoft's competitors copied it to their DOM implementations for exactly the same reason. It became part of a quasi-standard(now called "DOM Level 0").
1990 年代 Netscape 的竞争对手 Microsoft 不得不为MSHTML DOM复制该功能,以便为 Netscape 编写的代码也可以在带有JScript(1.0) 的Internet Explorer (3.0) 中运行。微软的竞争对手出于完全相同的原因将其复制到他们的 DOM 实现中。它成为准标准(现在称为“ DOM Level 0”)的一部分。
Then came the DOM Level 2 HTML Specification, a continuing effort to standardize and extend common features of existing DOM implementations at the time. A W3C Recommendation since 2003-01-09, its ECMAScript Language Bindingspecifies that items of HTMLCollection
s can be accessed by their name orIDwith the bracket property accessor syntax [
…]
, equivalent to calling the namedItem()
methodof the object implementing the HTMLCollection
interface.
然后是 DOM Level 2 HTML 规范,这是对当时现有 DOM 实现的通用功能进行标准化和扩展的持续努力。自 2003-01-09 以来的 W3C 建议,其ECMAScript 语言绑定指定HTMLCollection
可以使用括号属性访问器语法...通过其名称或ID访问 s 的项目,相当于调用实现该接口的对象的方法。[
]
namedItem()
HTMLCollection
form
element objects and element objects for form controls in forms are items of HTMLCollection
s in the W3C DOM, HTMLDocument::forms
and HTMLFormElement::elements
, respectively. But for backwards compatibility in browsers,
form
表单中的表单控件的元素对象和元素对象分别HTMLCollection
是 W3C DOM 中的s项HTMLDocument::forms
和HTMLFormElement::elements
。但是为了在浏览器中向后兼容,
document.forms["myForm"].elements["myControl"]
needs to be equivalentto
需要等价于
document.myForm.myControl
So, with the implementations of W3C DOM Level 2 HTML interfaces at the latest, this feature started to apply to elements with ID(id
attribute value) as well (which can be seen in Chromium, for example).
因此,随着最新的 W3C DOM Level 2 HTML 接口的实现,此功能也开始应用于具有 ID(id
属性值)的元素(例如,可以在 Chromium 中看到)。
As a result, the convenience feature introduced in JavaScript? 16 years ago still bites you like a bug in client-side DOM scripting today.
因此,JavaScript 中引入的便利特性?16 年前仍然像今天客户端 DOM 脚本中的错误一样咬你。
If you avoid using the same name or ID for form controls and forms that you use as identifier of user-defined functions, and that are already used for built-in form properties (like action
, submit
, and reset
), then this becomes less of an issue. Also, it is a bad idea to use the same identifier for the function and one of its arguments as (confusing code aside) that makes the function object inaccessible from within the function (the Variable Object of the function context comes first in its scope chain).
如果您避免对用作用户定义函数标识符的表单控件和表单使用相同的名称或 ID,并且已用于内置表单属性(如action
、submit
、 和reset
),那么这不会成为问题. 此外,为函数使用相同的标识符及其参数之一是一个坏主意(将混淆代码放在一边)使函数对象无法从函数内部访问(函数上下文的变量对象首先出现在其作用域链中) )。
回答by Christoph
IE automatically reserves a var ID = domElement;
in the global space for each DOM-Element with an ID
. Some other browsers adopted this behaviour.
IE 自动var ID = domElement;
为每个 DOM 元素在全局空间中保留一个ID
. 其他一些浏览器采用了这种行为。
Always try to avoid using same IDs and varnames! Alternatively, use your own namespace in JS to avoid the collisions.
始终尽量避免使用相同的 ID 和变量名!或者,在 JS 中使用您自己的命名空间来避免冲突。
EDIT:
编辑:
I don't know why one of your examples fails, while the other one works. It might be a simple timing/order of execution -issue caused by the wrapping <form>
.
我不知道为什么你的一个例子失败了,而另一个有效。这可能是由 wrapping 引起的一个简单的时间/执行顺序问题<form>
。
回答by georg
It looks to me like the form
tag creates an additional scope around inline event handlers, and form elements are defined as variables in this local scope:
在我看来,form
标签围绕内联事件处理程序创建了一个额外的作用域,并且表单元素被定义为这个局部作用域中的变量:
<form>
<element id="foo"....
<element onclick="foo is a local variable here"
No variables are auto-defined globally in my tests, but this may vary across browsers/modes.
在我的测试中,没有全局自动定义变量,但这可能因浏览器/模式而异。