我有两个几乎相同的简单JS小提琴,它们在选择更改时调用一个函数。在这两种情况下,函数名称都与select ID相同,但是由于某种原因,第一个小提琴可以正常工作,而第二个小提琴则失败,并出现JavaScript错误is not a function

http://jsfiddle.net/ AZkfy / 7 /-在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>

<select id='border' name='border' onchange='border(this.value)'>
    <option value='foo'>foo</option>
    <option value='bar'>bar</option>
</select>


首先,我无法理解为什么第一个可以正常运行,而第二个却不能运行。 >

评论

对我而言,第二个作品和第一个作品失败(在chrome中测试)。您能添加您的浏览器吗?

这对我有用jsfiddle.net/ZdhRe

#1 楼

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

如果您使用表单控件(这里是select元素)是表单(form元素的后代)的一部分,则表示Form元素的form对象在控件的事件处理程序属性值的代码范围链中排在倒数第二(第二个) -next是表单控制对象本身,其次是该代码的变量对象。

JavaScript™由Brendan Eich(当时为Netscape)设计,是一种易于初学者使用的编程语言。并且可以很好地与HTML文档配合使用(作为Sun Java的补充;因此,名称经常混乱)。因为在早期,语言和(Netscape)DOM API是一种,所以(过度)简化也适用于DOM API:Form对象具有以其表示的形式包含的控件名称,作为其属性的名称。引用相应的表单控件对象。 IOW,您可以编写

myForm.border


,它是符合标准(W3C DOM Level 2 HTML)但又向后兼容的专有缩写。 br />
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 DOM中实现HTMLFormElement接口的对象)之后排在最后。
但是,此处border引用的表单控制对象是不可调用的(不实现ECMAScript内部的[[Call]]方法或实现该方法,以便在调用时引发异常)。因此,如果您尝试使用border(this.value)调用对象,则会引发TypeError异常,您应该在脚本控制台中看到该异常(例如Chromium 16.0.912.77 [Developer Build 118311 Linux ])。

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

随后出现了DOM级别2 HTML规范,这是在标准和扩展现有DOM实现的通用功能方面的持续努力。时间。自2003年1月9日起成为W3C建议书,其ECMAScript语言绑定指定可以使用方括号属性访问器语法HTMLCollection[来通过名称或ID访问]的项,等同于调用实现namedItem()的对象的HTMLCollection方法interface。

form元素对象和表单中用于表单控件的元素对象分别是W3C DOM中的HTMLCollection s项,分别是HTMLDocument::formsHTMLFormElement::elements。但是为了实现浏览器的向后兼容性,

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

需要与

document.myForm.myControl


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

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

如果您避免在表单控件和用作用户定义函数的标识符的表单控件和已经用于内置表单属性(例如actionsubmitreset)的表单控件和表单中使用相同的名称或ID,则该数量会减少一个问题。同样,对函数及其参数之一使用相同的标识符(而不是混淆代码)也是一个坏主意,这会使函数对象无法从函数内部访问(函数上下文的可变对象在其作用域链中排在首位)。

评论


@Christoph,不客气:)由于问题是关于ID的,因此我对此进行了进一步研究,并添加了解释,W3C DOM 2 HTML如何将此问题与元素ID关联。还应注意,表单对象在范围链中排在倒数第三。如果不是为了消除歧义,我们就不需要编写this.value,只需编写value(!)。

– PointedEars
2012年2月7日在0:32



#2 楼

IE会为每个DOM元素自动为var ID = domElement;在全局空间中保留ID。其他一些浏览器也采用了这种方式。或者,在JS中使用您自己的命名空间来避免冲突。

编辑:这可能是由包装<form>引起的简单执行时间/顺序。

评论


正如我在回答中提到的那样,我认为该形式可能会延迟dom元素对var的占用。因此,该函数首先分配给var,随后它被dom元素覆盖。

– Christophh
2012年2月6日在10:38



对于更改,这与MSHTML的通过命名作用域链中全局宿主对象的属性可访问的用于命名/ ID元素的制造对象无关,并且与计时无关。这是一个遗留的作用域链问题,并且也发生在“标准遵从模式”中(而名称/ ID问题在除IE之外的多个浏览器中均未出现)。

– PointedEars
2012年2月6日在12:56



@Christoph HTML5规范中提到了您所描述的内容:whatwg.org/specs/web-apps/current-work/multipage / ...,但是将来可能会删除它。

–玛蒂亚斯·拜恩斯(Mathias Bynens)
2012年2月6日14:03



@Mathias我不知道,这也适用于某些元素的name属性。因此,问题的确实是,为option元素创建变量的过程掩盖了附加到全局对象的函数。

– Christophh
2012年2月6日下午14:53

@Christoph为select元素创建一个属性。

– PointedEars
2012年2月6日在17:13

#3 楼

http://jsfiddle.net/x79ey/1/

在我看来,form标记围绕内联事件处理程序创建了一个附加作用域,并且表单元素在此局部作用域中定义为变量:

<form>
    <element id="foo"....
    <element onclick="foo is a local variable here"


我的测试中没有全局自动定义变量,但是在浏览器/模式之间可能会有所不同。