Di recente il team di Chrome ha annunciato che stiamo spostando le proprietà DOM nella catena del prototipo. Questa modifica, implementata in Chrome 43 (beta a partire da metà aprile 2015), rende Chrome più conforme alla specifica Web IDL e alle implementazioni di altri browser, come IE e Firefox. Modifica: chiarimenti I browser basati su WebKit meno recenti non sono attualmente compatibili con le specifiche, ma Safari ora lo è.
Il nuovo comportamento è positivo sotto molti aspetti. Il GDPR:
- Migliora la compatibilità sul web (IE e Firefox lo fanno già) grazie alla conformità alle specifiche.
- Ti consente di creare in modo coerente ed efficiente getter/setter su ogni oggetto DOM.
- Aumenta la possibilità di eseguire attacchi alla programmazione DOM. Ad esempio, ti consentirà di implementare 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, una ipotetica specifica 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, ti consigliamo di 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 le altre proprietà DOM in Chrome, avresti dovuto creare la nuova proprietà in ogni istanza, il che sarebbe stato molto inefficiente per ogni HTMLDivElement
nella pagina.
Queste modifiche sono importanti per la coerenza, le prestazioni e la standardizzazione della piattaforma web, ma possono causare alcuni problemi per gli 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 utilizzano hasOwnProperty
per verificare la presenza di una proprietà in un oggetto. Questo non funzionerà più come dall'API perché gli attributi DOM ora fanno parte della catena del prototipo e hasOwnProperty
ispeziona solo gli oggetti attuali per verificare se sono definiti.
Prima di Chrome 42 e nelle versioni successive, il seguente comando restituiva true
.
> div = document.createElement("div");
> div.hasOwnProperty("isContentEditable");
true
A partire da Chrome 43, restituirà false
.
> div = document.createElement("div");
> div.hasOwnProperty("isContentEditable");
false
Ora, 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, in quanto controllerà la proprietà nell'intera catena del prototipo.
if("isContentEditable" in div) {
// We have support!!
}
Object.getOwnPropertyDescriptor sull'istanza dell'oggetto DOM non restituirà più un descrittore di proprietà per gli attributi
Se il tuo sito deve recuperare il descrittore della proprietà per un attributo in un oggetto DOM, ora dovrai seguire la catena del prototipo.
Per ottenere la descrizione della proprietà in Chrome 42 e versioni precedenti, avresti dovuto:
> Object.getOwnPropertyDescriptor(div, "isContentEditable");
Object {value: "", writable: true, enumerable: true, configurable: true}
A partire da Chrome 43, in questo caso verrà restituito undefined
.
> Object.getOwnPropertyDescriptor(div, "isContentEditable");
undefined
Ciò significa che per ottenere il descrittore della proprietà per la proprietà isContentEditable
dovrai seguire la catena del prototipo come segue:
> Object.getOwnPropertyDescriptor(HTMLElement.prototype, "isContentEditable");
Object {get: function, set: function, enumerable: false, configurable: false}
JSON.stringify non eseguirà più la serializzazione degli attributi DOM
JSON.stringify
non esegue la serializzazione delle proprietà DOM presenti nel prototipo. Ad esempio, questo può influire sul tuo sito se stai tentando di serializzare un oggetto come PushSubscription della notifica push.
In Chrome 42 e versioni precedenti, la seguente operazione avrebbe funzionato:
> JSON.stringify(subscription);
{
"endpoint": "https://something",
"subscriptionId": "SomeID"
}
A partire da Chrome 43, le proprietà definite nel prototipo non verranno serializzate e verrà restituito un oggetto vuoto.
> JSON.stringify(subscription);
{}
Dovrai fornire il tuo metodo di serializzazione, ad esempio potresti procedere nel seguente modo:
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 in proprietà di sola lettura in modalità rigorosa genera un errore
La scrittura nelle proprietà di sola lettura dovrebbe generare un'eccezione quando utilizzi la modalità rigorosa. Ad esempio:
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 ed eseguito silenziosamente l'esecuzione, anche se isContentEditable
non sarebbe stato modificato.
// Chrome 42 and earlier behavior
> foo();
false // isContentEditable
false // isContentEditable (after writing to read-only property)
Ora, in Chrome 43 e versioni successive, verrà lanciata 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 parliamo.
Ho notato un problema su un sito, cosa devo fare?
Ottima domanda. La maggior parte dei problemi relativi ai siti si basa sul fatto che un sito ha scelto di eseguire il rilevamento della presenza di attributi con il metodo getOwnProperty
. Questo viene fatto principalmente quando un proprietario del sito ha scelto come target solo i browser WebKit meno recenti. Un sviluppatore può fare alcune cose:
- Segnala un problema relativo al sito interessato nel nostro tracker dei problemi (di Chrome)
- Segnala un problema nel radar di WebKit e fai riferimento a https://bugs.webkit.org/show_bug.cgi?id=49739
In genere, mi interessa seguire questa modifica
- Bug originale del 2010: https://bugs.chromium.org/p/chromium/issues/detail?id=43394 - nota: contiene la maggior parte del lavoro.
- Revisione del codice per il commit