Это устаревшая проблема цепочки областей видимости, возникшая в JavaScript 1.0-1.3, когда не было никакого различия между языком программирования и тем, что мы сейчас называем DOM API (тогда «Динамический HTML»).
Если элемент управления формы (здесь: элемент select
) является частью формы (потомок элемента form
), то объект Form
, представляющий элемент form
, занимает третье-следующее место в область видимости кода в значениях атрибутов обработчика событий элемента управления (второй-следующий - сам объект элемента управления формы, следующий - объект-переменная этого кода).
JavaScript ™ был спроектирован Бренданом Айхом (тогда в Netscape) как язык программирования, который прост в использовании для начинающих и который хорошо работает с HTML-документами (как дополнение к Java от Sun; отсюда и постоянно запутывающее имя). Поскольку в те ранние времена язык и (Netscape) DOM API были единым целым, это (чрезмерное) упрощение также применялось к DOM API: A 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 Global Object, который идет последним, после Form
объекта (объекта, реализующего интерфейс HTMLFormElement
в W3C DOM), в цепочке областей действия.
Однако объект управления формой, на который здесь ссылается border
, не вызывается (не реализует встроенный в ECMAScript метод [[Call]]
или реализует его так, чтобы он вызывал исключение при вызове). Поэтому, если вы попытаетесь вызвать объект с border(this.value)
, будет выдано исключение TypeError
, которое вы должны увидеть в консолях скрипта (например, «TypeError: border не является функцией» в инструментах разработчика Chromium 16.0.912.77 [ Разработчик Build 118311 Linux]).
Microsoft, конкурент Netscape в 1990-х годах, пришлось скопировать эту функцию для MSHTML DOM , чтобы код, написанный для Netscape, также работал в Internet Explorer (3.0) с JScript (1.0). И конкуренты Microsoft скопировали его в свои реализации DOM по той же причине. Он стал частью квази-стандарта (теперь называется " DOM Level 0 ").
Затем появилась HTML-спецификация DOM уровня 2 - постоянная попытка стандартизировать и расширить общие возможности существующих реализаций DOM того времени. Рекомендация W3C с 2003-01-09, ее Связывание языка ECMAScript указывает, что элементы HTMLCollection
s могут быть доступны по их имени или ID с помощью Синтаксис метода доступа к скобкам [
… ]
, эквивалентный вызову namedItem()
метода объекта, реализующего интерфейс HTMLCollection
.
Элементы
form
и элементы элементов для элементов управления форм в формах - это элементы HTMLCollection
s в DOM W3C, HTMLDocument::forms
и HTMLFormElement::elements
, соответственно. Но для обратной совместимости в браузерах,
document.forms["myForm"].elements["myControl"]
должен быть эквивалент
document.myForm.myControl
Итак, с последними реализациями HTML-интерфейсов W3C DOM Level 2 эта функция стала применяться и к элементам с идентификатором (id
значение атрибута), а также (что можно увидеть в Chromium). например).
В результате удобная функция, появившаяся в JavaScript ™ 16 лет назад, все еще кусает вас, как баг в сценариях DOM на стороне клиента.
Если вы избегаете использования того же имени или идентификатора для элементов управления формы и форм, которые вы используете в качестве идентификатора пользовательских функций и которые уже используются для встроенных свойств формы (например, action
, submit
и reset
), тогда это становится меньшей проблемой. Кроме того, плохой идеей является использование того же идентификатора для функции и одного из ее аргументов, что и (смущая код в стороне), что делает объект функции недоступным изнутри функции (объект переменной контекста функции занимает первое место в своей цепочке областей действия ).