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