一尘不染

为什么JS函数名称与元素ID冲突?

javascript

我有两个几乎相同的简单JS小提琴,它们在选择更改时调用一个函数。在这两种情况下,函数名称都与select
ID相同,但是由于某种原因,第一个小提琴可以正常工作,而第二个小提琴却因JavaScript错误而失败 is not a function :在FF9(Linux),Chromium16(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>

在FF9(Linux),Chromium16(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>

首先 ,我不明白为什么第一个可以正常工作,而第二个却不能工作。

第二 -关于冲突的JS函数名称和元素ID是否有JS规范或限制?


阅读 413

收藏
2020-04-25

共1个答案

一尘不染

这是一个源于JavaScript 1.0到1.3的遗留范围链问题,当时编程语言和我们现在称为DOMAPI(当时称为“动态HTML”)之间没有区别。

如果您的表单控件(此处为:select元素)是表单的一部分(form元素的后代),那么Form表示该form元素的对象在控件的事件处理程序属性值(第二个-接下来是表单控件对象本身,其次是该代码的变量对象)。

JavaScript™由BrendanEich(当时为Netscape)设计,是一种编程语言,对于初学者来说易于使用,并且可以很好地与HTML文档配合使用(作为SunJava的补充;因此,名称经常被混淆)。因为在那些早期语言和(网景)DOM API是一个,这个(过)简化施加到DOMAPI,以及:甲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-internal[[Call]]方法或实现该方法,以便在调用时引发异常)。因此,如果您尝试使用调用对象border(this.value)TypeError则会引发异常,您应该在脚本控制台中看到该异常(例如Chromium16.0.912.77[DeveloperBuild118311Linux]的开发人员工具中的“ TypeError:border不是函数”) 。

作为1990年代Netscape的竞争对手,Microsoft必须复制MSHTML DOM的该功能,以便为Netscape编写的代码也可以在Internet
Explorer(3.0)和JScript(1.0)中运行。微软的竞争对手出于完全相同的原因将其复制到其DOM实现中。它成为
准标准 (现在称为“ DOM Level 0 ”)的一部分。

然后是DOM Level 2HTML规范,这是对当前DOM实现的通用功能进行标准化和扩展的持续努力。自2003年1月9日起成为W3C建议书,其ECMAScript语言绑定指定HTMLCollections的项可以使用方括号属性访问器语法…
通过其名称 ID 进行访问,等同于调用实现该接口的对象的方法[``]``namedItem()``HTMLCollection

form表单中用于表单控件的元素对象和元素对象分别HTMLCollection是W3CDOMHTMLDocument::forms和中的项HTMLFormElement::elements。但是为了向后兼容浏览器,

document.forms["myForm"].elements["myControl"]

必须 等同

document.myForm.myControl

因此,最迟在W3C DOM 2级HTML接口的实现中,此功能也开始应用于 ID为id属性值)的 元素
(例如,在Chromium中可以看到)。

结果,在16年前JavaScript™中引入的便利功能仍然像今天的客户端DOM脚本中的错误一样使您咬伤。

如果避免使用相同的名称或ID为表单控件和表格,你作为用户定义的函数标识符使用,并且已经用于内置形式属性(比如actionsubmitreset),那么这成为一个问题的更小。同样,对函数及其参数之一使用相同的标识符(而不是混淆代码)也是一个坏主意,这会使函数对象无法从函数内部进行访问(函数上下文的变量对象在其作用域链中排在首位)
)。

2020-04-25