Attributi DOM ora nella catena dei prototipi

Il team di Chrome ha recentemente annunciato il trasferimento delle proprietà DOM alla catena di prototipi. Questa modifica, implementata in Chrome 43 (beta a partire da metà aprile 2015), allinea ulteriormente Chrome alle specifiche Web IDL e alle implementazioni di altri browser, come IE e Firefox. Modifica: chiarito I browser WebKit meno recenti non sono attualmente compatibili con le specifiche, ma adesso lo è Safari.

Questo nuovo comportamento è positivo sotto molti aspetti. Il GDPR:

  • Migliora la compatibilità su tutto il Web (IE e Firefox lo fanno già) rispettando le specifiche.
  • Consente di creare getter/setter in modo coerente ed efficiente su ogni oggetto DOM.
  • Aumenta l'hackbilità della programmazione DOM. Ad esempio, potrai implementare i polyfill che ti consentono di emulare in modo efficiente le funzionalità mancanti in alcuni browser e librerie JavaScript che sostituiscono i comportamenti degli attributi DOM predefiniti.

Ad esempio, un'ipotetica specifica di W3C include alcune nuove funzionalità chiamate isSuperContentEditable e il browser Chrome non le implementa, ma è possibile eseguire il "polyfill" o emulare la funzionalità con una libreria. In qualità di sviluppatore della libreria, probabilmente vorrai utilizzare prototype come segue per creare un polyfill efficiente:

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

Prima di questa modifica, per coerenza con altre proprietà DOM in Chrome, dovevi creare la nuova proprietà per ogni istanza, cosa che per ogni HTMLDivElement nella pagina sarebbe stata molto inefficiente.

Queste modifiche sono importanti per la coerenza, le prestazioni e la standardizzazione della piattaforma web, ma possono causare alcuni problemi agli sviluppatori. Se facevi affidamento su questo comportamento a causa della compatibilità precedente tra Chrome e WebKit, ti invitiamo a controllare il tuo sito e a leggere il riepilogo delle modifiche di seguito.

Riepilogo delle modifiche

L'utilizzo di hasOwnProperty su un'istanza di oggetto DOM ora restituirà false

A volte gli sviluppatori usano hasOwnProperty per verificare la presenza di una proprietà su un oggetto. Non funzionerà più come secondo la specifica perché gli attributi DOM ora fanno parte della catena di prototipi e hasOwnProperty esamina solo gli oggetti correnti per verificare se sono stati definiti.

Prima dell'inclusione di Chrome 42, viene restituito true.

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

true

A partire da Chrome 43, restituirà false.

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

false

Questo ora significa che se vuoi verificare che isContentEditable sia disponibile nell'elemento, dovrai controllare il prototipo nell'oggetto HTMLElement. Ad esempio, HTMLDivElement eredita da HTMLElement, che definisce la proprietà isContentEditable.

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

true

Non sei obbligato a utilizzare hasOwnProperty. Ti consigliamo di utilizzare l'operando in molto più semplice, poiché ciò verificherà la proprietà sull'intera catena di prototipi.

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

Object.getOwnPropertyDescriptor sull'istanza di oggetto DOM non restituirà più un descrittore di proprietà per gli attributi

Se il tuo sito deve ottenere il descrittore della proprietà per un attributo su un oggetto DOM, ora devi seguire la catena di prototipi.

Se avessi voluto ottenere la descrizione della proprietà in Chrome 42 e versioni precedenti, avresti dovuto farlo:

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

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

In questo scenario, Chrome 43 e versioni successive restituiranno undefined.

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

undefined

Il che significa che per ottenere il descrittore di proprietà per la proprietà isContentEditable, devi seguire la catena di prototipi come segue:

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

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

JSON.stringify non serializzerà più gli attributi DOM

JSON.stringify non serializza le proprietà DOM presenti nel prototipo. Ad esempio, questo può influire sul sito se stai tentando di serializzare un oggetto come PushSubscription delle notifiche push.

Chrome 42 e versioni precedenti avrebbero funzionato quanto segue:

> JSON.stringify(subscription);

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

Chrome 43 e versioni successive non serializzeranno le proprietà che si trovano su definite nel prototipo e ti verrà restituito un oggetto vuoto.

> JSON.stringify(subscription);

{}

Dovrai fornire un tuo metodo di serializzazione, ad esempio potresti svolgere le seguenti operazioni:

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

La scrittura nelle proprietà di sola lettura in modalità restrittiva genera un errore

La scrittura nelle proprietà di sola lettura dovrebbe generare un'eccezione quando utilizzi la modalità restrittiva. Ad esempio, considera quanto segue:

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

In Chrome 42 e versioni precedenti, la funzione avrebbe continuato e continuato in modalità silenziosa l'esecuzione della funzione, anche se isContentEditable non sarebbe stato modificato.

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

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

A partire da Chrome 43 e versioni successive verrà generata un'eccezione.

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

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

Ho un problema, cosa devo fare?

Segui le indicazioni o lascia un commento qui sotto e parliamone.

Ho visto un sito con un problema, cosa devo fare?

Ottima domanda. La maggior parte dei problemi relativi ai siti si basa sul fatto che un sito ha scelto di attivare il rilevamento della presenza di attributi con il metodo getOwnProperty, che viene eseguito principalmente quando il proprietario di un sito ha scelto come target solo browser WebKit meno recenti. Uno sviluppatore può eseguire due operazioni:

  • Segnala un problema relativo al sito interessato nel nostro Issue Tracker di Chrome
  • Segnala un problema sul radar WebKit e fai riferimento a https://bugs.webkit.org/show_bug.cgi?id=49739

In genere sono interessato a seguire questa modifica