这是一个遗留范围链问题,起源于 JavaScript 1.0 到 1.3,当时编程语言和我们现在称之为 DOM API(当时的“动态 HTML”)之间没有区别。
如果您的表单控件(此处:select
元素)是表单的一部分(form
元素的后代),则Form
表示该form
元素的对象在控件的事件处理程序属性值(第二个-下一个是表单控件对象本身,下一个是该代码的变量对象)。
JavaScript™ 是由 Brendan Eich(当时在 Netscape 工作)设计的,是一种易于初学者使用的编程语言,并且可以很好地处理 HTML 文档(作为 Sun 的 Java 的补充;因此名称总是令人困惑)。因为在早期语言和 (Netscape) DOM API 是一回事,这种(过度)简化也适用于 DOM API:一个Form
对象具有包含在表单中的控件名称,它表示为它的属性名称参考对应的表单控件对象。IOW,你可以写
myForm.border
这是符合标准(W3C DOM Level 2 HTML)的专有简写,但同样向后兼容
document.forms["myForm"].elements["border"]
现在,如果你在一个窗体控件的事件处理程序的属性值使用窗体控件的名称的形式,像
<form …>
<… name="border" onchange='border(this.value)' …>
</form>
这就像你写了半专有
<form …>
<… name="border" onchange='this.form.border(this.value)' …>
</form>
或符合标准
<form …>
<… name="border" onchange='this.form.elements["border"](this.value)' …>
</form>
因为一个潜在的全球border()
功能是的属性的ECMAScript其去年来的时候,全局对象之后的Form
对象(实施对象HTMLFormElement
在W3C DOM接口),作用域链。
但是,这里引用的表单控件对象border
是不可调用的(没有实现 ECMAScript 内部的[[Call]]
方法或实现它以便在调用时抛出异常)。因此,如果您尝试使用 调用对象border(this.value)
,TypeError
则会引发异常,您应该在脚本控制台中看到该异常(例如 Chromium 16.0.912.77 [Developer Build 118311 Linux] 的开发人员工具中的“TypeError: border is not a function”) .
1990 年代 Netscape 的竞争对手 Microsoft 不得不为MSHTML DOM复制该功能,以便为 Netscape 编写的代码也可以在带有JScript (1.0) 的Internet Explorer (3.0) 中运行。微软的竞争对手出于完全相同的原因将其复制到他们的 DOM 实现中。它成为准标准(现在称为“ DOM Level 0 ”)的一部分。
然后是 DOM Level 2 HTML 规范,这是对当时现有 DOM 实现的通用功能进行标准化和扩展的持续努力。自 2003-01-09 以来的 W3C 建议,其ECMAScript 语言绑定指定HTMLCollection
可以使用括号属性访问器语法...通过其名称或 ID访问 s 的项目,相当于调用实现接口的对象的方法。[
]
namedItem()
HTMLCollection
form
表单中的表单控件的元素对象和元素对象分别HTMLCollection
是 W3C DOM 中的s项HTMLDocument::forms
和HTMLFormElement::elements
。但是为了在浏览器中向后兼容,
document.forms["myForm"].elements["myControl"]
需要等价于
document.myForm.myControl
因此,随着最新的 W3C DOM Level 2 HTML 接口的实现,此功能也开始应用于具有 ID(id
属性值)的元素(例如,可以在 Chromium 中看到)。
因此,16 年前在 JavaScript™ 中引入的便利特性仍然像今天客户端 DOM 脚本中的错误一样让您感到厌烦。
如果您避免对用作用户定义函数标识符的表单控件和表单使用相同的名称或 ID,并且已用于内置表单属性(如action
、submit
、 和reset
),那么这不会成为问题. 此外,为函数使用相同的标识符及其参数之一是一个坏主意(将混淆代码放在一边)使函数对象无法从函数内部访问(函数上下文的变量对象首先出现在其作用域链中) )。