Mise à jour des attributs DOM dans la chaîne de prototypes

L'équipe Chrome a récemment annoncé que nous transférons les propriétés DOM vers la chaîne de prototypes. Cette modification, implémentée dans Chrome 43 (version bêta à partir de mi-avril 2015), rapproche Chrome de la spécification Web IDL et des implémentations d'autres navigateurs, tels qu'IE et Firefox. Modification: clarification   Les anciens navigateurs basés sur WebKit ne sont actuellement pas compatibles avec la spécification, mais Safari l'est.

Ce nouveau comportement est positif à bien des égards.

  • Améliore la compatibilité sur le Web (IE et Firefox le font déjà) en respectant la spécification.
  • Vous permet de créer des getters/setters de manière cohérente et efficace sur chaque objet DOM.
  • Augmente la possibilité de piratage de la programmation DOM. Par exemple, vous pourrez implémenter des polyfills qui vous permettront d'émuler efficacement les fonctionnalités manquantes dans certains navigateurs et bibliothèques JavaScript qui remplacent les comportements d'attribut DOM par défaut.

Par exemple, une spécification W3C hypothétique inclut une nouvelle fonctionnalité appelée isSuperContentEditable et le navigateur Chrome ne l'implémente pas, mais il est possible de "polyfiller" ou d'émuler la fonctionnalité avec une bibliothèque. En tant que développeur de la bibliothèque, vous souhaitez naturellement utiliser prototype comme suit pour créer un polyfill efficace:

Object.defineProperty(HTMLDivElement.prototype, "isSuperContentEditable", {
    get: function() { return true; },
    set: function() { /* some logic to set it up */ },
});

Avant ce changement, pour assurer la cohérence avec les autres propriétés DOM de Chrome, vous deviez créer la nouvelle propriété dans chaque instance, ce qui était très inefficace pour chaque HTMLDivElement de la page.

Ces modifications sont importantes pour la cohérence, les performances et la standardisation de la plate-forme Web, mais elles peuvent poser des problèmes aux développeurs. Si vous vous appuyiez sur ce comportement en raison de la compatibilité antérieure entre Chrome et WebKit, nous vous encourageons à vérifier votre site et à consulter le résumé des modifications ci-dessous.

Résumé des modifications

L'utilisation de hasOwnProperty sur une instance d'objet DOM renvoie désormais false.

Les développeurs utilisent parfois hasOwnProperty pour vérifier la présence d'une propriété sur un objet. Cela ne fonctionnera plus conformément aux spécifications, car les attributs DOM font désormais partie de la chaîne de prototypes et hasOwnProperty n'inspecte que les objets actuels pour voir s'ils sont définis dessus.

Avant Chrome 42 et y compris cette version, la valeur true était renvoyée.

> div = document.createElement("div");
> div.hasOwnProperty("isContentEditable");

true

À partir de Chrome 43, la valeur renvoyée est false.

> div = document.createElement("div");
> div.hasOwnProperty("isContentEditable");

false

Cela signifie que si vous souhaitez vérifier que isContentEditable est disponible sur l'élément, vous devez vérifier le prototype sur l'objet HTMLElement. Par exemple, HTMLDivElement hérite de HTMLElement, qui définit la propriété isContentEditable.

> HTMLElement.prototype.hasOwnProperty("isContentEditable");

true

Vous n'êtes pas obligé d'utiliser hasOwnProperty. Nous vous recommandons d'utiliser l'opérande in, beaucoup plus simple, car elle vérifie la propriété sur l'ensemble de la chaîne de prototypes.

if("isContentEditable" in div) {
    // We have support!!
}

Object.getOwnPropertyDescriptor sur l'instance d'objet DOM ne renverra plus de descripteur de propriété pour les attributs

Si votre site doit obtenir le descripteur de propriété d'un attribut sur un objet DOM, vous devez désormais suivre la chaîne de prototypes.

Pour obtenir la description de la propriété dans Chrome 42 et versions antérieures, procédez comme suit:

> Object.getOwnPropertyDescriptor(div, "isContentEditable");

Object {value: "", writable: true, enumerable: true, configurable: true}

À partir de Chrome 43, undefined sera renvoyé dans ce scénario.

> Object.getOwnPropertyDescriptor(div, "isContentEditable");

undefined

Pour obtenir le descripteur de propriété de la propriété isContentEditable, vous devez suivre la chaîne de prototypes comme suit:

> Object.getOwnPropertyDescriptor(HTMLElement.prototype, "isContentEditable");

Object {get: function, set: function, enumerable: false, configurable: false}

JSON.stringify ne sérialisera plus les attributs DOM

JSON.stringify ne sérialise pas les propriétés DOM présentes sur le prototype. Par exemple, cela peut avoir un impact sur votre site si vous essayez de sérialiser un objet tel que le PushSubscription de la notification push.

Avec Chrome 42 et versions antérieures, la procédure suivante aurait fonctionné:

> JSON.stringify(subscription);

{
    "endpoint": "https://something",
    "subscriptionId": "SomeID"
}

À partir de Chrome 43, les propriétés définies sur le prototype ne seront plus sérialisées, et un objet vide sera renvoyé.

> JSON.stringify(subscription);

{}

Vous devrez fournir votre propre méthode de sérialisation. Par exemple, vous pouvez procéder comme suit:

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);

Écrire dans des propriétés en lecture seule en mode strict génère une erreur

L'écriture dans des propriétés en lecture seule est censée générer une exception lorsque vous utilisez le mode strict. Prenons l'exemple suivant:

function foo() {
    "use strict";
    var d = document.createElement("div");
    console.log(d.isContentEditable);
    d.isContentEditable = 1;
    console.log(d.isContentEditable);
}

Dans Chrome 42 et versions antérieures, la fonction aurait continué à s'exécuter en mode silencieux, même si isContentEditable n'aurait pas été modifié.

// Chrome 42 and earlier behavior
> foo();

false // isContentEditable
false // isContentEditable (after writing to read-only property)

À partir de Chrome 43, une exception sera générée.

// Chrome 43 and onwards behavior
> foo();

false
Uncaught TypeError: Cannot set property isContentEditable of #<HTMLElement> which has only a getter

J'ai un problème. Que dois-je faire ?

Suivez les instructions ou laissez un commentaire ci-dessous pour discuter.

J'ai vu un site présentant un problème. Que dois-je faire ?

Excellente question. La plupart des problèmes liés aux sites proviennent du fait qu'un site a choisi de détecter la présence d'attributs avec la méthode getOwnProperty. Cela se produit généralement lorsqu'un propriétaire de site n'a ciblé que les anciens navigateurs WebKit. Un développeur peut effectuer plusieurs actions:

  • Signaler un problème concernant le site concerné dans notre outil de suivi des problèmes (Chrome)
  • Signalez un problème sur le radar WebKit et référencez https://bugs.webkit.org/show_bug.cgi?id=49739.

Je souhaite suivre ce changement