为什么JS函数名称与元素ID冲突? [英] Why JS function name conflicts with element ID?

查看:68
本文介绍了为什么JS函数名称与元素ID冲突?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个几乎相同的简单JS调用select函数来调用函数。在这两种情况下,函数名都与select ID相同,但出于某种原因,第一个小提琴可以正常工作,而第二个小提琴因JavaScript错误而失败 不是函数



http://jsfiddle.net/AZkfy / 7 / - 在FF9(Linux),Chromium 16(Linux),IE8(Windows)中运行良好:

 <脚本> 
函数边框(边框){alert(border); }
< / script>

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



http://jsfiddle.net/cYVzk/ - 在FF9(Linux),Chromium 16(Linux),IE8(Windows)中失败:

 < script> 
函数边框(边框){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规范或有关冲突的JS函数名称和元素ID的限制?

解决方案

这是一个遗留范围链问题,源于JavaScript 1.0到1.3,当时没有区分编程语言和我们现在称之为如果你的表单控件(这里:a 选择元素)是表单的一部分(表单元素的后代),然后是表单表示 form 元素是控件事件处理程序属性值中代码的作用域链中的第三个下一个(第二个下一个是表单控件对象本身,下一个是该代码的变量对象)。

JavaScript™由Brendan E设计ich(当时在Netscape)作为一种易于使用的编程语言,适用于初学者,并且适用于HTML文档(作为Sun Java的补充;因此一直是令人困惑的名字)。因为在早期的语言和(Netscape)DOM API中,这种(过)简化也适用于DOM API:一个 Form 对象具有包含在表单中的控件的名称,它表示为其属性的名称指的是相应的表单控制对象。 IOW,您可以编写

  myForm.border 

这是符合标准的专有速记( W3C DOM Level 2 HTML ),但同样向后兼容

  document.forms [myForm ] .elements [border] 

现在,如果您在事件中使用表单控件的名称 -

中的表单控件的handler属性值

,例如

 < form ...> 
< ... name =borderonchange ='border(this.value)'...>
< / form>

与您编写半专有的
相同

 < form ...> 
< ... name =borderonchange ='this.form.border(this.value)'...>
< / form>

或符合标准的

 < form ...> 
< ... name =borderonchange ='this.form.elements [border](this.value)'...>
< / form>

因为潜在的全局 border()函数是 ECMAScript 全局对象的最后一个属性,位于<$ c之后在范围链中,$ c> Form 对象(一个在W3C DOM中实现 HTMLFormElement 接口的对象)。



但是,由 border 引用的表单控制对象不可调用(不实现ECMAScript内部 [[调用]] 方法或实现它,以便它在调用时引发异常)。因此,如果您尝试使用 border(this.value)调用对象,则会引发 TypeError 异常,您应该在脚本控制台中看到(例如Chromium的开发工具16.0.912.77 [Developer Build 118311 Linux]中的TypeError:border不是函数)。

Microsoft ,Netscape在20世纪90年代的竞争对手不得不复制该功能的 MSHTML DOM ,以便为Netscape编写的代码也可以在Internet Explorer(3.0)中运行,其中 JScript (1.0)。微软的竞争对手也将其复制到他们的DOM实现中,原因完全相同。它成为准标准的一部分(现在称为 DOM Level 0 )。

然后是DOM Level 2 HTML Specification,这是继续努力标准化和扩展现有DOM的常见功能当时的实施。自2003-01-09以来的W3C推荐标准,其 ECMAScript语言绑定指定可以通过名称​​或 ID 访问 HTMLCollection 括号属性访问器语法 [ ... ] ,相当于调用 namedItem() method 对象实现 HTMLCollection 接口。



form 元素对象并且表单中的表单控件的元素对象是W3C DOM中的 HTMLCollection s项, HTMLDocument :: forms HTMLFormElement :: elements ,相应的年。但为了向后兼容浏览器,

  document.forms [myForm]。elements [myControl] 

需要与相同



< pre $ document.myForm.myControl

的W3C DOM Level 2 HTML接口,此功能也开始适用于ID为( id 属性值)的元素(它可以例如,在Chromium中可以看到)。



因此,16年前JavaScript™中引入的便利功能仍然让您感到像客户端DOM脚本中的错误。

如果您避免使用相同的名称或ID作为您用作用户定义函数的标识符的表单控件和表单,在表单属性中(比如 action submit reset ),那么这就变成了一个问题。另外,对函数和它的一个参数使用相同的标识符(使混淆代码处于旁边)使函数对象在函数内不可访问(函数上下文的变量对象在其作用域链中首先出现)是一个坏主意)。


I've got two almost identical simple JS fiddles calling a function on select change. Function name is the same as select ID in both cases, but for some reason the first fiddle works just fine, and the second one fails with a JavaScript error is not a function:

http://jsfiddle.net/AZkfy/7/ - works fine in 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>

and

http://jsfiddle.net/cYVzk/ - fails in FF9 (Linux), Chromium 16 (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>

First of all I fail to understand why the first one works fine, and the second one fails.

Second - are there any JS specifications or restrictions regarding the conflicting JS function names and element ID?

解决方案

This is a legacy scope chain issue originating from JavaScript 1.0 to 1.3 when there was no distinction between the programming language and what we now call a DOM API ("Dynamic HTML" back then).

If your form control (here: a select element) is part of a form (descendant of a form element), then the Form object that represents the form element is third-next in the scope chain of code in the control's event-handler attribute values (second-next is the form control object itself, next is the Variable Object of that code).

JavaScript™ was designed by Brendan Eich (then at Netscape) as a programming language that is easy to use for beginners and that works well with HTML documents (as complement to Sun's Java; hence the ever-confusing name). Because in those early days language and (Netscape) DOM API were one, this (over)simplification applied to the DOM API as well: 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, you can write

myForm.border

which is the proprietary shorthand of the standards-compliant (W3C DOM Level 2 HTML), but equally backwards-compatible

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

Now, if you use a form control's name in an event-handler attribute value of a form control in a form, like

<form …>
  <… name="border" onchange='border(this.value)' …>
</form>

that is the same as if you had written the half-proprietary

<form …>
  <… name="border" onchange='this.form.border(this.value)' …>
</form>

or the standards-compliant

<form …>
  <… name="border" onchange='this.form.elements["border"](this.value)' …>
</form>

because a potential global border() function is a property of the ECMAScript Global Object which comes last, after the Form object (an object implementing the HTMLFormElement interface in the W3C DOM), in the scope chain.

However, the form control object referred here by border is not callable (does not implement the ECMAScript-internal [[Call]] method or implements it so that it throws an exception when called). So if you try to call the object with border(this.value), a TypeError exception is thrown, which you should see in the script consoles (like "TypeError: border is not a function" in the Developer Tools of Chromium 16.0.912.77 [Developer Build 118311 Linux]).

Microsoft, Netscape's competitor in the 1990s, had to copy that feature for the MSHTML DOM so that code written for Netscape would also run in Internet Explorer (3.0), with JScript (1.0). And Microsoft's competitors copied it to their DOM implementations for exactly the same reason. It became part of a quasi-standard (now called "DOM Level 0").

Then came the DOM Level 2 HTML Specification, a continuing effort to standardize and extend common features of existing DOM implementations at the time. A W3C Recommendation since 2003-01-09, its ECMAScript Language Binding specifies that items of HTMLCollections can be accessed by their name or ID with the bracket property accessor syntax [], equivalent to calling the namedItem() method of the object implementing the HTMLCollection interface.

form element objects and element objects for form controls in forms are items of HTMLCollections in the W3C DOM, HTMLDocument::forms and HTMLFormElement::elements, respectively. But for backwards compatibility in browsers,

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

needs to be equivalent to

document.myForm.myControl

So, with the implementations of W3C DOM Level 2 HTML interfaces at the latest, this feature started to apply to elements with ID (id attribute value) as well (which can be seen in Chromium, for example).

As a result, the convenience feature introduced in JavaScript™ 16 years ago still bites you like a bug in client-side DOM scripting today.

If you avoid using the same name or ID for form controls and forms that you use as identifier of user-defined functions, and that are already used for built-in form properties (like action, submit, and reset), then this becomes less of an issue. Also, it is a bad idea to use the same identifier for the function and one of its arguments as (confusing code aside) that makes the function object inaccessible from within the function (the Variable Object of the function context comes first in its scope chain).

这篇关于为什么JS函数名称与元素ID冲突?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆