.prop() frente a .attr()

Resuelto Naftali asked hace 13 años • 18 respuestas

Entonces jQuery 1.6 tiene la nueva función prop().

$(selector).click(function(){
    //instead of:
    this.getAttribute('style');
    //do i use:
    $(this).prop('style');
    //or:
    $(this).attr('style');
})

o en este caso hacen lo mismo?

Y si tengo que cambiar a prop(), ¿todas las llamadas antiguas attr()se interrumpirán si cambio a 1.6?

ACTUALIZAR

selector = '#id'

$(selector).click(function() {
    //instead of:
    var getAtt = this.getAttribute('style');
    //do i use:
    var thisProp = $(this).prop('style');
    //or:
    var thisAttr = $(this).attr('style');

    console.log(getAtt, thisProp, thisAttr);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.0/jquery.min.js"></script>
<div id='id' style="color: red;background: orange;">test</div>
Expandir fragmento

(ver también este violín: http://jsfiddle.net/maniator/JpUF2/ )

La consola registra getAttributecomo una cadena y attrcomo una cadena, pero como prop, CSSStyleDeclaration¿por qué? ¿Y cómo afecta eso a mi codificación en el futuro?

Naftali avatar May 04 '11 02:05 Naftali
Aceptado

Actualización 1 de noviembre de 2012

Mi respuesta original se aplica específicamente a jQuery 1.6. Mi consejo sigue siendo el mismo, pero jQuery 1.6.1 cambió ligeramente las cosas: frente a la pila prevista de sitios web rotos, el equipo de jQuery volvió attr()a algo cercano (pero no exactamente igual) a su antiguo comportamiento para los atributos booleanos . John Resig también escribió en su blog sobre ello . Puedo ver la dificultad en la que se encontraban, pero todavía no estoy de acuerdo con su recomendación de preferir attr().

Respuesta original

Si alguna vez solo ha usado jQuery y no el DOM directamente, este podría ser un cambio confuso, aunque definitivamente es una mejora conceptual. Sin embargo, no es tan bueno para los millones de sitios que usan jQuery y que se romperán como resultado de este cambio.

Resumiré los principales problemas:

  • Normalmente quieres prop()en lugar de attr().
  • En la mayoría de los casos, prop()hace lo que attr()solía hacer. Reemplazar llamadas a attr()con prop()en su código generalmente funcionará.
  • Las propiedades son generalmente más sencillas de manejar que los atributos. El valor de un atributo solo puede ser una cadena, mientras que una propiedad puede ser de cualquier tipo. Por ejemplo, la checkedpropiedad es booleana, la stylepropiedad es un objeto con propiedades individuales para cada estilo, la sizepropiedad es un número.
  • Cuando existen tanto una propiedad como un atributo con el mismo nombre, normalmente la actualización de uno actualizará el otro, pero este no es el caso para ciertos atributos de entradas, como y: valuepara checkedestos atributos, la propiedad siempre representa el estado actual mientras que el El atributo (excepto en versiones antiguas de IE) corresponde al valor/verificación predeterminado de la entrada (reflejado en la propiedad defaultValue/ defaultChecked).
  • Este cambio elimina parte de la capa mágica de jQuery pegada delante de los atributos y propiedades, lo que significa que los desarrolladores de jQuery tendrán que aprender un poco sobre la diferencia entre propiedades y atributos. Ésto es una cosa buena.

Si eres un desarrollador de jQuery y estás confundido por todo este asunto de propiedades y atributos, debes dar un paso atrás y aprender un poco sobre ello, ya que jQuery ya no se esfuerza tanto por protegerte de estas cosas. Para las palabras autorizadas pero algo secas sobre el tema, están las especificaciones: DOM4 , HTML DOM , DOM Nivel 2 , DOM Nivel 3 . La documentación DOM de Mozilla es válida para la mayoría de los navegadores modernos y es más fácil de leer que las especificaciones, por lo que su referencia DOM puede resultarle útil. Hay una sección sobre propiedades de elementos .

Como ejemplo de cómo las propiedades son más sencillas de manejar que los atributos, considere una casilla de verificación que está inicialmente marcada. Aquí hay dos posibles piezas de HTML válido para hacer esto:

<input id="cb" type="checkbox" checked>
<input id="cb" type="checkbox" checked="checked">

Entonces, ¿cómo puedo saber si la casilla de verificación está marcada con jQuery? Busque en Stack Overflow y normalmente encontrará las siguientes sugerencias:

  • if ( $("#cb").attr("checked") === true ) {...}
  • if ( $("#cb").attr("checked") == "checked" ) {...}
  • if ( $("#cb").is(":checked") ) {...}

En realidad, esto es lo más sencillo del mundo que se puede hacer con la checkedpropiedad booleana, que ha existido y ha funcionado perfectamente en todos los principales navegadores con secuencias de comandos desde 1995:

if (document.getElementById("cb").checked) {...}

La propiedad también hace que marcar o desmarcar la casilla sea trivial:

document.getElementById("cb").checked = false

En jQuery 1.6, esto sin ambigüedades se convierte en

$("#cb").prop("checked", false)

La idea de utilizar el checkedatributo para escribir una casilla de verificación es inútil e innecesaria. La propiedad es lo que necesitas.

  • No es obvio cuál es la forma correcta de marcar o desmarcar la casilla de verificación usando el checkedatributo
  • El valor del atributo refleja el estado visible predeterminado en lugar del actual (excepto en algunas versiones anteriores de IE, lo que dificulta aún más las cosas). El atributo no le dice nada sobre si la casilla de verificación de la página está marcada. Consulte http://jsfiddle.net/VktA6/49/ .
Tim Down avatar May 03 '2011 23:05 Tim Down

Creo que Tim lo dijo bastante bien , pero retrocedamos:

Un elemento DOM es un objeto, una cosa en la memoria. Como la mayoría de los objetos en programación orientada a objetos, tiene propiedades . También, por separado, tiene un mapa de los atributos definidos en el elemento (generalmente provenientes del marcado que el navegador leyó para crear el elemento). Algunas de las propiedades del elemento obtienen sus valores iniciales de atributos con nombres iguales o similares ( valueobtiene su valor inicial del atributo "valor"; hrefobtiene su valor inicial del atributo "href", pero no es exactamente el mismo valor; classNamedel atributo "clase"). Otras propiedades obtienen sus valores iniciales de otras maneras: por ejemplo, la parentNodepropiedad obtiene su valor en función de cuál es su elemento principal; un elemento siempre tiene una stylepropiedad, tenga o no un atributo de "estilo".

Consideremos este ancla en una página en http://example.com/testing.html:

<a href="foo.html" class="test one" name="fooAnchor" id="fooAnchor">Hi</a>

Algo de arte ASCII gratuito (y omitiendo muchas cosas):

+------------------------------------------------+
| ElementoAnclaHTML |
+------------------------------------------------+
| href: "http://ejemplo.com/foo.html" |
| nombre: "fooAnchor" |
| identificación: "fooAnchor" |
| className: "prueba uno" |
| atributos: +-----------------------------+ |
| | href: "foo.html" | |
| | nombre: "fooAnchor" | |
| | identificación: "fooAnchor" | |
| | clase: "prueba uno" | |
| +-----------------------------+ |
+------------------------------------------------+

Tenga en cuenta que las propiedades y atributos son distintos.

Ahora bien, aunque son distintas, debido a que todo esto evolucionó en lugar de diseñarse desde cero, varias propiedades se escriben de nuevo al atributo del que derivaron si las configuras. Pero no todos lo hacen, y como puede ver hrefarriba, el mapeo no siempre es una simple "transmisión del valor", a veces hay interpretación involucrada.

Cuando hablo de que las propiedades son propiedades de un objeto, no hablo en abstracto. Aquí hay algo de código que no es jQuery:

const link = document.getElementById("fooAnchor");
console.log(link.href);                 // Shows "http://example.com/foo.html"
console.log(link.getAttribute("href")); // Shows "foo.html"

El linkobjeto es algo real y puede ver que existe una distinción real entre acceder a una propiedad y acceder a un atributo .

Como dijo Tim, la gran mayoría de las veces queremos trabajar con propiedades. En parte, eso se debe a que sus valores (incluso sus nombres) tienden a ser más consistentes en todos los navegadores. Generalmente solo queremos trabajar con atributos cuando no hay ninguna propiedad relacionada con ellos (atributos personalizados), o cuando sabemos que para ese atributo en particular, el atributo y la propiedad no son 1:1 (como con " hrefhref" arriba) .

Las propiedades estándar se establecen en las distintas especificaciones DOM:

  • DOM2 HTML (en gran parte obsoleto, consulte la especificación HTML en su lugar)
  • Núcleo DOM2 (obsoleto)
  • Núcleo DOM3 (obsoleto)
  • DOM4

Estas especificaciones tienen índices excelentes y recomiendo tener enlaces a ellas a mano; Los utilizo todo el tiempo.

Los atributos personalizados incluirían, por ejemplo, cualquier data-xyzatributo que pueda poner en elementos para proporcionar metadatos a su código (ahora que eso es válido a partir de HTML5, siempre y cuando se ciña al data-prefijo). (Las versiones recientes de jQuery te dan acceso a data-xyzelementos a través de la datafunción, pero esa función no es solo un acceso para data-xyzatributos [hace más y menos que eso]; a menos que realmente necesites sus características, usaría la attrfunción para interactuar con data-xyzatributo.)

La attrfunción solía tener una lógica complicada para obtener lo que pensaban que querías, en lugar de obtener literalmente el atributo. Combinaba los conceptos. Mudarse a propy attrtenía como objetivo desconcertarlos. Brevemente, en la versión 1.6.0, jQuery fue demasiado lejos en ese sentido, pero rápidamente se volvió a agregar funcionalidad para attrmanejar las situaciones comunes en las que las personas usan attrcuando técnicamente deberían usar prop.

T.J. Crowder avatar May 04 '2011 14:05 T.J. Crowder

Este cambio ha tardado en llegar para jQuery. Durante años, se han contentado con una función attr()cuyo nombre recuperaba principalmente propiedades DOM, no el resultado que se esperaría del nombre. La segregación de attr()y prop()debería ayudar a aliviar parte de la confusión entre los atributos HTML y las propiedades DOM. $.fn.prop()toma la propiedad DOM especificada, mientras que $.fn.attr()toma el atributo HTML especificado.

Para comprender completamente cómo funcionan, aquí hay una explicación ampliada sobre la diferencia entre los atributos HTML y las propiedades DOM:

Atributos HTML

Sintaxis:

<body onload="foo()">

Propósito: permite que el marcado tenga datos asociados para eventos, renderizado y otros fines.

Visualización: Atributos HTML el atributo de clase se muestra aquí en el cuerpo. Es accesible a través del siguiente código:

var attr;
attr = document.body.getAttribute("class");
//IE 8 Quirks and below
attr = document.body.getAttribute("className");

Los atributos se devuelven en forma de cadena y pueden ser inconsistentes de un navegador a otro. Sin embargo, pueden ser vitales en algunas situaciones. Como se ejemplificó anteriormente, el modo Quirks de IE 8 (y siguientes) espera el nombre de una propiedad DOM en get/set/removeAttribute en lugar del nombre del atributo. Ésta es una de las muchas razones por las que es importante conocer la diferencia.

Propiedades DOM

Sintaxis:

document.body.onload = foo;

Propósito: Da acceso a propiedades que pertenecen a nodos de elementos. Estas propiedades son similares a los atributos, pero solo se puede acceder a ellas a través de JavaScript. Esta es una diferencia importante que ayuda a aclarar el papel de las propiedades DOM. Tenga en cuenta que los atributos son completamente diferentes de las propiedades , ya que esta asignación de controlador de eventos es inútil y no recibirá el evento (el cuerpo no tiene un evento de carga, solo un atributo de carga).

Visualización: Propiedades DOM

Aquí, verá una lista de propiedades en la pestaña "DOM" en Firebug. Estas son propiedades DOM. Inmediatamente notarás algunos de ellos, ya que los habrás utilizado antes sin saberlo. Sus valores son los que recibirás a través de JavaScript.

Documentación

  • JavaScript: la guía definitiva de David Flanagan
  • Atributos HTML, Centro de desarrollo de Mozilla
  • Propiedades del elemento DOM, Centro de desarrollo de Mozilla

Ejemplo

HTML:<textarea id="test" value="foo"></textarea>

JavaScript:alert($('#test').attr('value'));

En versiones anteriores de jQuery, esto devolvía una cadena vacía. En 1.6, devuelve el valor adecuado, foo.

Sin haber echado un vistazo al nuevo código para ninguna de las funciones, puedo decir con confianza que la confusión tiene más que ver con la diferencia entre los atributos HTML y las propiedades DOM que con el código en sí. Con suerte, esto te ha aclarado algunas cosas.

-Mate

 avatar May 03 '2011 20:05