这是一个遗留的范围链问题,起源于JavaScript1.0到1.3,当时编程语言与我们现在所称的DOMAPI(当时的“动态HTML”)没有区别。
如果窗体控件(此处:select
元素)是窗体的一部分(form
元素),则Form
对象,该对象表示form
元素是控件事件处理程序属性值范围链中的第三个-下一个(第二个-下一个是表单控件对象本身,其次是该代码的变量对象)。
JavaScriptJava是由BrendanEich(当时在Netscape)设计的,它是一种编程语言,对于初学者来说很容易使用,并且可以很好地处理™文档(作为对Sun的JAVA的补充;因此它是一个永远令人困惑的名字)。因为在早期语言和(Netscape)DOM API是一种,这种简化(过度)也适用于DOMAPI:A Form
对象具有包含在其表示为引用相应窗体控件对象的属性名称的窗体中的控件的名称。..你可以写
myForm.border
它是符合标准的专有速记(W3C DOM级别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
接口在W3CDOM中),在作用域链中。
但是,此处引用的窗体控件对象由border
不可调用(不实现ecmaScript-内部的[[Call]]
方法或实现它,以便在调用时抛出异常)。因此,如果您试图用border(this.value)
..TypeError
抛出异常,您应该在脚本控制台中看到这个异常(比如Chromium16.0.912.77[Developer Build 118311 linux]的开发工具中的“TypeError:边框不是函数”)。
20世纪90年代,Netscape的竞争对手微软(Microsoft)不得不将该功能复制到MSHTML DOM因此,为Netscape编写的代码也将在InternetExplorer(3.0)中运行,JScript(1.0)。微软的竞争对手也出于同样的原因将其复制到DOM实现中。它成为了准标准(现称“DOM级0").
然后是DOMLevel2HTML规范,这是当时标准化和扩展现有DOM实现的通用特性的持续努力。自2003-01-09年度起获W3C推荐,ECMAScript语言绑定指定HTMLCollection
s可以通过它们的名称访问。或 ID使用括号属性访问器语法。[
…]
,相当于调用namedItem()
方法对象的HTMLCollection
接口。
form
窗体中窗体控件的元素对象和元素对象是HTMLCollection
在W3C DOM中,HTMLDocument::forms
和HTMLFormElement::elements
分别。但是为了在浏览器中向后兼容,
document.forms["myForm"].elements["myControl"]
需要等价物到
document.myForm.myControl
因此,最迟在W3CDOMLevel2HTML接口的实现中,这个特性开始应用于具有ID的元素 (id
属性值)(例如,在Chrome中可以看到)。
因此,16年前在JavaScriptDOM中引入的方便特性至今仍像客户端DOM脚本中的bug一样咬你一口。
如果避免对窗体控件和窗体使用相同的名称或ID,将其用作用户定义函数的标识符,并且已用于内置窗体属性(如action
, submit
,和reset
),这就不再是什么问题了。此外,对函数及其参数之一使用相同的标识符也是个坏主意,因为这使得函数对象无法从函数内部访问(函数上下文的变量对象位于其作用域链的第一位)。