Recientemente, el equipo de Chrome anunció que trasladaremos las propiedades del DOM a la cadena de prototipos. Este cambio, implementado en Chrome 43 (versión beta a partir de mediados de abril de 2015), permite que Chrome cumpla con las especificaciones de Web IDL y las implementaciones de otros navegadores, como IE y Firefox. Edición: aclarado: Los navegadores anteriores basados en WebKit, actualmente no son compatibles con la especificación, pero ahora Safari.
El nuevo comportamiento es positivo en muchos sentidos. Por ejemplo:
- Mejora la compatibilidad en la Web (IE y Firefox ya lo hacen) al cumplir con las especificaciones.
- Te permite crear métodos get y set de manera coherente y eficiente en cada objeto DOM.
- Aumenta la capacidad de hackeo de la programación DOM. Por ejemplo, te permitirá implementar polyfills que te permiten emular de forma eficiente la funcionalidad que falta en algunos navegadores y bibliotecas JavaScript que anulan los comportamientos predeterminados de los atributos del DOM.
Por ejemplo, una especificación W3C hipotética incluye una funcionalidad nueva llamada isSuperContentEditable
y el navegador Chrome no la implementa, pero es posible "polyfill" o emular la función con una biblioteca. Como desarrollador de bibliotecas, te gustaría usar prototype
de la siguiente manera para crear un polyfill eficiente:
Object.defineProperty(HTMLDivElement.prototype, "isSuperContentEditable", {
get: function() { return true; },
set: function() { /* some logic to set it up */ },
});
Antes de este cambio, para mantener la coherencia con otras propiedades del DOM en Chrome, habrías tenido que crear la nueva propiedad en cada instancia, lo que para cada HTMLDivElement
en la página sería muy ineficiente.
Estos cambios son importantes para la coherencia, el rendimiento y la estandarización de la plataforma web, pero pueden causarles algunos problemas a los desarrolladores. Si dependías de este comportamiento debido a la compatibilidad con versiones heredadas entre Chrome y WebKit, te recomendamos que revises tu sitio y veas el resumen de los cambios que aparece a continuación.
Resumen de cambios
Si usas hasOwnProperty
en una instancia de objeto del DOM, ahora se mostrará false
.
A veces, los desarrolladores usan hasOwnProperty
para verificar la presencia de una propiedad en un objeto. Esto ya no funcionará como según las especificaciones porque los atributos del DOM ahora forman parte de la cadena del prototipo y hasOwnProperty
solo inspecciona los objetos actuales para ver si están definidos en ellos.
Antes de Chrome 42 inclusive, lo siguiente mostraría true
.
> div = document.createElement("div");
> div.hasOwnProperty("isContentEditable");
true
A partir de la versión 43 de Chrome, mostrará false
.
> div = document.createElement("div");
> div.hasOwnProperty("isContentEditable");
false
Esto significa que, si quieres verificar que isContentEditable
esté disponible en el elemento, deberás verificar el prototipo en el objeto HTMLElement. Por ejemplo, HTMLDivElement
hereda de HTMLElement
, que define la propiedad isContentEditable
.
> HTMLElement.prototype.hasOwnProperty("isContentEditable");
true
No estás limitado a usar hasOwnProperty
. Recomendamos usar el operando in
mucho más simple, ya que este verificará la propiedad en toda la cadena del prototipo.
if("isContentEditable" in div) {
// We have support!!
}
Object.getOwnPropertyDescriptor en la instancia de objeto del DOM ya no mostrará un descriptor de propiedad para los atributos.
Si tu sitio necesita obtener el descriptor de propiedad para un atributo en un objeto DOM, ahora deberás seguir la cadena del prototipo.
Si quisieras obtener la descripción de la propiedad en Chrome 42 y versiones anteriores, habrías hecho lo siguiente:
> Object.getOwnPropertyDescriptor(div, "isContentEditable");
Object {value: "", writable: true, enumerable: true, configurable: true}
En Chrome 43 y versiones posteriores, se mostrará undefined
en este caso.
> Object.getOwnPropertyDescriptor(div, "isContentEditable");
undefined
Esto significa que, para obtener el descriptor de propiedad de la propiedad isContentEditable
, deberás seguir la cadena del prototipo de la siguiente manera:
> Object.getOwnPropertyDescriptor(HTMLElement.prototype, "isContentEditable");
Object {get: function, set: function, enumerable: false, configurable: false}
JSON.stringify ya no serializará atributos del DOM
JSON.stringify
no serializa las propiedades del DOM que se encuentran en el prototipo. Por ejemplo, esto puede afectar a tu sitio si intentas serializar un objeto como PushSubscription de las notificaciones push.
En Chrome 42 y versiones anteriores, habría funcionado lo siguiente:
> JSON.stringify(subscription);
{
"endpoint": "https://something",
"subscriptionId": "SomeID"
}
A partir de Chrome 43, no se serializarán las propiedades que están definidas en el prototipo y se mostrará un objeto vacío.
> JSON.stringify(subscription);
{}
Deberás proporcionar tu propio método de serialización, por ejemplo, puedes hacer lo siguiente:
function stringifyDOMObject(object)
{
function deepCopy(src) {
if (typeof src != "object")
return src;
var dst = Array.isArray(src) ? [] : {};
for (var property in src) {
dst[property] = deepCopy(src[property]);
}
return dst;
}
return JSON.stringify(deepCopy(object));
}
var s = stringifyDOMObject(domObject);
Si escribes en propiedades de solo lectura en el modo estricto, se arrojará un error
Se supone que la escritura en propiedades de solo lectura genera una excepción cuando usas el modo estricto. Por ejemplo, considera lo siguiente:
function foo() {
"use strict";
var d = document.createElement("div");
console.log(d.isContentEditable);
d.isContentEditable = 1;
console.log(d.isContentEditable);
}
En Chrome 42 y versiones anteriores, la función habría continuado y continuaba ejecutando de forma silenciosa la función, aunque isContentEditable
no habría cambiado.
// Chrome 42 and earlier behavior
> foo();
false // isContentEditable
false // isContentEditable (after writing to read-only property)
A partir de Chrome 43, se producirá una excepción.
// Chrome 43 and onwards behavior
> foo();
false
Uncaught TypeError: Cannot set property isContentEditable of #<HTMLElement> which has only a getter
Tengo un problema, ¿qué debo hacer?
Sigue las instrucciones o deja un comentario a continuación y hablemos.
Vi un sitio con un problema. ¿Qué debo hacer?
Muy buena pregunta. La mayoría de los problemas con los sitios se basan en el hecho de que un sitio haya elegido realizar la detección de presencias de atributos con el método getOwnProperty
. Esto ocurre principalmente cuando el propietario del sitio solo se orienta a navegadores de WebKit más antiguos. Los desarrolladores pueden realizar las siguientes acciones:
- Informa un problema sobre el sitio afectado en nuestra herramienta de seguimiento de errores (de Chrome)
- Informa sobre un problema en el radar WebKit y consulta https://bugs.webkit.org/show_bug.cgi?id=49739
En general, me interesa hacer un seguimiento de este cambio
- Error original de 2010: https://bugs.chromium.org/p/chromium/issues/detail?id=43394. Nota: Tiene la mayor parte del trabajo en ello.
- Revisión de código para confirmación