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

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

问题描述

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

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/ - 在 FF9 (Linux)、Chromium 16 (Linux)、IE8 (Windows):

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>

http://jsfiddle.net/cYVzk/ - 在 FF9 (Linux)、Chromium 16 (Linux)、IE8 (视窗):

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.

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

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

推荐答案

这是一个遗留的作用域链问题,起源于 JavaScript 1.0 到 1.3,当时编程语言和我们现在称之为 DOM API(动态HTML").

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).

如果您的表单控件(此处:select 元素)是表单(form 元素的后代)的一部分,则 Form 表示 form 元素的对象是控件的事件处理程序属性值中代码作用域链中的第三个下一个(第二个下一个是表单控件对象本身,下一个是它的变量对象代码).

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™ 是由 Brendan Eich(当时在 Netscape)设计的,是一种易于初学者使用且适用于 HTML 文档的编程语言(作为 Sun 的 Java 的补充;因此名称一直令人困惑).因为在早期语言和 (Netscape) DOM API 是一回事,这种(过度)简化也适用于 DOM API:Form 对象具有包含在表单中的控件的名称,它表示为引用相应表单的属性名称控制对象.IOW,你可以写

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

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

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>

这就像你写了半专有

<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 接口的对象),在作用域链中.

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.

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

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 在 1990 年代的竞争对手,不得不为 MSHTML DOM 以便为 Netscape 编写的代码也可以在 Internet Explorer (3.0) 中运行,JScript (1.0).微软的竞争对手出于完全相同的原因将其复制到他们的 DOM 实现中.它成为准标准(现在称为DOM 级别 0").

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").

然后是 DOM Level 2 HTML 规范,这是对当时现有 DOM 实现的通用功能进行标准化和扩展的持续努力.自 2003-01-09 以来的 W3C 建议,其 ECMAScript 语言绑定 指定HTMLCollection 的项目可以通过它们的名称​​或 ID 使用括号属性访问器语法[],相当于调用了实现HTMLCollection 接口的对象的namedItem() 方法.

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 元素对象和表单中的表单控件的元素对象是 W3C DOM 中 HTMLCollection 的项,HTMLDocument::formsHTMLFormElement::elements.但为了在浏览器中向后兼容,

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"]

需要等价

document.myForm.myControl

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

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).

因此,16 年前在 JavaScript™ 中引入的便利功能今天仍然像客户端 DOM 脚本中的错误一样困扰着您.

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

如果您避免对用作用户定义函数标识符的表单控件和表单使用相同的名称或 ID,并且已用于内置表单属性(如 actionsubmitreset),那么这就不那么重要了.此外,为函数使用相同的标识符及其参数之一是一个坏主意(将混淆代码放在一边)使函数对象无法从函数内部访问(函数上下文的变量对象首先出现在其作用域链中)).

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天全站免登陆