¿Por qué el nombre de la función JS entra en conflicto con el ID del elemento?
Tengo dos violines JS simples casi idénticos que llaman a una función al cambiar de selección. El nombre de la función es el mismo que el ID de selección en ambos casos, pero por alguna razón el primer violín funciona bien y el segundo falla con un error de JavaScript is not a function
:
http://jsfiddle.net/AZkfy/7/ - funciona bien en 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>
y
http://jsfiddle.net/cYVzk/ - falla en 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>
En primer lugar, no entiendo por qué el primero funciona bien y el segundo falla.
En segundo lugar , ¿existen especificaciones o restricciones de JS con respecto a los nombres de funciones de JS y el ID de elemento en conflicto?
Este es un problema de cadena de alcance heredado que se origina desde JavaScript 1.0 a 1.3 cuando no había distinción entre el lenguaje de programación y lo que ahora llamamos API DOM ("HTML dinámico" en aquel entonces).
Si su control de formulario (aquí: un select
elemento) es parte de un formulario (descendiente de un form
elemento), entonces el Form
objeto que representa el form
elemento es el tercero en la cadena de alcance de código en los valores de atributos del controlador de eventos del control (segundo- el siguiente es el objeto de control del formulario en sí, el siguiente es el objeto variable de ese código).
JavaScript™ fue diseñado por Brendan Eich (entonces en Netscape) como un lenguaje de programación fácil de usar para principiantes y que funciona bien con documentos HTML (como complemento de Java de Sun; de ahí el nombre siempre confuso). Debido a que en aquellos primeros días el lenguaje y la API DOM (Netscape) eran uno, esta (sobre)simplificación se aplicaba también a la API DOM: un Form
objeto tiene los nombres de los controles contenidos en el formulario que representa como los nombres de sus propiedades que Consulte los objetos de control de formulario correspondientes . OIA, puedes escribir
myForm.border
que es la abreviatura patentada de compatible con los estándares ( W3C DOM Nivel 2 HTML ), pero igualmente compatible con versiones anteriores
document.forms["myForm"].elements["border"]
Ahora, si usa el nombre de un control de formulario en un valor de atributo de controlador de eventos de un control de formulario en un formulario , como
<form …>
<… name="border" onchange='border(this.value)' …>
</form>
eso es lo mismo que si hubieras escrito la media propiedad
<form …>
<… name="border" onchange='this.form.border(this.value)' …>
</form>
o el que cumple con las normas
<form …>
<… name="border" onchange='this.form.elements["border"](this.value)' …>
</form>
porque una border()
función global potencial es una propiedad del objeto global ECMAScript que viene en último lugar, después del Form
objeto (un objeto que implementa la HTMLFormElement
interfaz en el DOM del W3C), en la cadena de alcance.
Sin embargo, el objeto de control de formulario al que se hace referencia aquí border
no se puede invocar (no implementa el [[Call]]
método interno de ECMAScript ni lo implementa de modo que genere una excepción cuando se llama). Entonces, si intenta llamar al objeto con border(this.value)
, se genera una TypeError
excepción, que debería ver en las consolas de script (como "TypeError: el borde no es una función" en las Herramientas de desarrollo de Chromium 16.0.912.77 [Desarrollador Build 118311 Linux]) .
Microsoft, el competidor de Netscape en la década de 1990, tuvo que copiar esa característica para MSHTML DOM para que el código escrito para Netscape también se ejecutara en Internet Explorer (3.0), con JScript (1.0). Y los competidores de Microsoft lo copiaron en sus implementaciones DOM exactamente por la misma razón. Se convirtió en parte de un cuasi estándar (ahora llamado " DOM Nivel 0 ").
Luego vino la especificación HTML DOM Nivel 2, un esfuerzo continuo para estandarizar y ampliar las características comunes de las implementaciones DOM existentes en ese momento. Una recomendación del W3C desde el 9 de enero de 2003, su enlace de lenguaje ECMAScript especifica que HTMLCollection
se puede acceder a los elementos de s por su nombre o ID con la sintaxis del accesor de propiedad de corchetes [
... ]
, equivalente a llamar al namedItem()
método del objeto que implementa la HTMLCollection
interfaz.
form
Los objetos de elemento y los objetos de elemento para controles de formulario en formularios son elementos de HTMLCollection
s en el DOM del W3C HTMLDocument::forms
y HTMLFormElement::elements
, respectivamente. Pero para compatibilidad con versiones anteriores de los navegadores,
document.forms["myForm"].elements["myControl"]
debe ser equivalente a
document.myForm.myControl
Entonces, con las implementaciones de las interfaces HTML W3C DOM Nivel 2 a más tardar, esta característica también comenzó a aplicarse a elementos con ID ( valor de atributo) (que se puede ver en Chromium, por ejemplo).id
Como resultado, la característica de conveniencia introducida en JavaScript™ hace 16 años todavía te molesta como un error en las secuencias de comandos DOM del lado del cliente en la actualidad.
Si evita usar el mismo nombre o ID para los controles de formulario y los formularios que usa como identificador de funciones definidas por el usuario y que ya se usan para las propiedades de formulario integradas (como action
, submit
y reset
), entonces esto se vuelve un problema menor. . Además, es una mala idea usar el mismo identificador para la función y uno de sus argumentos (aparte del código confuso) que hace que el objeto de la función sea inaccesible desde dentro de la función (el objeto variable del contexto de la función viene primero en su cadena de alcance). ).
IE reserva automáticamente un var ID = domElement;
espacio global para cada elemento DOM con un archivo ID
. Algunos otros navegadores adoptaron este comportamiento.
¡Intente siempre evitar el uso de los mismos ID y nombres de usuario! Alternativamente, use su propio espacio de nombres en JS para evitar colisiones.
EDITAR:
No sé por qué uno de tus ejemplos falla y el otro funciona. Podría ser un simple problema de tiempo/orden de ejecución causado por el ajuste <form>
.