Почему имя функции JS конфликтует с идентификатором элемента?

У меня есть две почти одинаковые простые скрипты JS, вызывающие функцию при выборе смены. Имя функции совпадает с именем ID в обоих случаях, но по какой-то причине первая скрипка работает нормально, а вторая с ошибкой JavaScript is not a function:

http://jsfiddle.net/AZkfy/7/ - отлично работает в 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 (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 в отношении конфликтующих имен функций JS и идентификатора элемента?

Ответ 1

Это устаревшая проблема с цепочкой поставок, исходящая с JavaScript 1.0 до 1.3, когда не было различий между языком программирования и тем, что мы теперь называем DOM API (далее "Динамический HTML" ).

Если ваш элемент управления формой (здесь: a select) является частью формы (потомок элемента form), то объект form, который представляет элемент form, является третьим рядом в целая цепочка кода в значениях атрибута управляющего события-обработчика (второй-следующий - сам объект управления формой, следующий - переменный объект этого кода).

JavaScript ™ был разработан Бренданом Эйхом (затем в Netscape) в качестве языка программирования, который прост в использовании для новичков, и это хорошо работает с документами HTML (как дополнение к Sun Java, а значит, и к запутанному имени). Поскольку в те ранние годы язык и (Netscape) DOM API были одним, это (более) упрощение, применяемое к API DOM: Объект form имеет имена элементов управления, содержащиеся в форме, которую он представляет, как имена его свойств, которые относятся к соответствующим объектам управления формой. IOW, вы можете написать

myForm.border

который является собственной стенографией стандартно-совместимых (W3C DOM Level 2 HTML), но одинаково обратная совместимость

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

Теперь, если вы используете имя элемента управления формы в значении атрибута event-handler элемента управления формы в форме, например

<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 в DOM W3C), в цепочке областей видимости.

Однако объект управления формой, указанный здесь border, не может быть вызван (не реализует ECMAScript-внутренний метод [[Call]] или реализует его так, чтобы он вызывал исключение при вызове). Поэтому, если вы пытаетесь вызвать объект с помощью border(this.value), генерируется исключение TypeError, которое вы должны увидеть в консолях script (например, "TypeError: border не является функцией" в Developer Tools of Chromium 16.0. 912.77 [Developer Build 118311 Linux]).

Microsoft, конкуренту Netscape в 1990-х годах, пришлось скопировать эту функцию для MSHTML DOM, чтобы код, написанный для Netscape, также запускался в Интернете Explorer (3.0), JScript (1.0). И конкуренты Microsoft скопировали их в свои реализации DOM по той же причине. Он стал частью квазистандартного (теперь называемого DOM Level 0").

Затем появилась DOM Level 2 HTML Specification, продолжающаяся попытка стандартизации и расширения общих функций существующих реализаций DOM в то время. Рекомендация W3C с 2003-01-09, ее привязка языка ECMAScript указывает, что элементы HTMLCollection могут быть доступны по их имени или ID с синтаксисом доступа к атрибуту bracket [... ], что эквивалентно вызову метода namedItem() реализации объекта интерфейс HTMLCollection.

form Объекты элементов и объекты элементов для элементов управления формами в формах являются элементами HTMLCollection в DOM W3C, HTMLDocument::forms и HTMLFormElement::elements, соответственно. Но для обратной совместимости в браузерах

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

должен быть эквивалентен

document.myForm.myControl

Итак, с реализацией интерфейсов HTML W3C DOM Level 2, эта функция начала применяться к элементам с атрибутом ID (id) (что можно увидеть в Хром, например).

В результате удобная функция, введенная в JavaScript ™ 16 лет назад, все еще укусит вас как ошибку на скриптах DOM на стороне клиента.

Если вы не используете одно и то же имя или идентификатор для элементов формы и форм формы, которые вы используете в качестве идентификатора определяемых пользователем функций и которые уже используются для встроенных свойств формы (например, action, submit и reset), тогда это становится проблемой. Кроме того, это плохая идея использовать один и тот же идентификатор для функции и один из ее аргументов как (путающий код в сторону), что делает объект функции недоступным изнутри функции (объект Variable объекта функции входит в первую очередь в своей цепочке видимости).

Ответ 2

IE автоматически резервирует var ID = domElement; в глобальном пространстве для каждого DOM-элемента с помощью ID. Некоторые другие браузеры приняли это поведение.

Всегда старайтесь избегать использования одинаковых идентификаторов и varnames! В качестве альтернативы, используйте свое собственное пространство имен в JS, чтобы избежать столкновений.

EDIT:

Я не знаю, почему один из ваших примеров терпит неудачу, а другой работает. Это может быть простой момент/порядок выполнения -issue, вызванный оберткой <form>.