DOM-attributen nu in de prototypeketen

Het Chrome-team heeft onlangs aangekondigd dat we DOM-eigenschappen naar de prototypeketen verplaatsen . Deze wijziging, geïmplementeerd in Chrome 43 (bètaversie medio april 2015), brengt Chrome meer in lijn met de Web IDL-specificatie en de implementaties van andere browsers, zoals Internet Explorer en Firefox. Bewerking: verduidelijkt: oudere WebKit-gebaseerde browsers zijn momenteel niet compatibel met de specificatie, maar Safari is dat nu wel.

Het nieuwe gedrag is in veel opzichten positief. Het:

  • Verbetert de compatibiliteit op het web (IE en Firefox doen dit al) door te voldoen aan de specificatie.
  • Hiermee kunt u op consistente en efficiënte wijze getters/setters op elk DOM-object maken.
  • Verhoogt de hackbaarheid van DOM-programmering. Het stelt u bijvoorbeeld in staat om polyfills te implementeren waarmee u efficiënt functionaliteit kunt emuleren die ontbreekt in sommige browsers en JavaScript-bibliotheken die standaard DOM-attribuutgedrag overschrijven.

Een hypothetische W3C-specificatie bevat bijvoorbeeld een nieuwe functionaliteit genaamd isSuperContentEditable en de Chrome-browser implementeert deze niet. Het is echter wel mogelijk om de functie te "polyfillen" of te emuleren met een bibliotheek. Als bibliotheekontwikkelaar zou je het prototype natuurlijk als volgt willen gebruiken om een ​​efficiënte polyfill te maken:

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

Vóór deze wijziging moest u - ter wille van de consistentie met andere DOM-eigenschappen in Chrome - in elk exemplaar een nieuwe eigenschap aanmaken. Dit was zeer inefficiënt voor elk HTMLDivElement op de pagina.

Deze wijzigingen zijn belangrijk voor de consistentie, prestaties en standaardisatie van het webplatform, maar kunnen ook problemen opleveren voor ontwikkelaars. Als u op dit gedrag vertrouwde vanwege de verouderde compatibiliteit tussen Chrome en WebKit, raden we u aan uw site te controleren en het onderstaande overzicht van de wijzigingen te bekijken.

Samenvatting van wijzigingen

Het gebruik van hasOwnProperty op een DOM-objectinstantie retourneert nu false

Soms gebruiken ontwikkelaars hasOwnProperty om te controleren of een eigenschap aanwezig is op een object. Dit werkt niet meer volgens de specificaties , omdat DOM-attributen nu deel uitmaken van de prototypeketen en hasOwnProperty alleen de huidige objecten inspecteert om te zien of deze erop gedefinieerd is.

Vóór en inclusief Chrome 42 zou het volgende true retourneren.

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

true

Vanaf Chrome 43 wordt false geretourneerd.

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

false

Dit betekent dat als u wilt controleren of isContentEditable beschikbaar is op het element, u het prototype op het HTMLElement-object moet controleren. HTMLDivElement erft bijvoorbeeld van HTMLElement , dat de eigenschap isContentEditable definieert.

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

true

Je bent niet verplicht hasOwnProperty te gebruiken. We raden aan om de veel eenvoudigere in operand te gebruiken, omdat deze de eigenschap op de gehele prototypeketen controleert.

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

Object.getOwnPropertyDescriptor op DOM-objectinstantie retourneert geen eigenschapsdescriptor meer voor kenmerken

Als uw site de eigenschapsdescriptor voor een kenmerk van een DOM-object nodig heeft, moet u nu de prototypeketen volgen.

Als u de beschrijving van een eigenschap in Chrome 42 en ouder wilde ophalen, had u het volgende gedaan:

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

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

Chrome 43 en hoger retourneren in dit scenario undefined .

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

undefined

Om nu de eigenschapsdescriptor voor de eigenschap isContentEditable te verkrijgen, moet u de prototypeketen als volgt volgen:

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

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

JSON.stringify zal DOM-attributen niet langer serialiseren

JSON.stringify serialiseert geen DOM-eigenschappen die zich op het prototype bevinden. Dit kan bijvoorbeeld van invloed zijn op uw site als u een object zoals PushSubscription van Push Notification probeert te serialiseren.

In Chrome 42 en ouder zou het volgende hebben gewerkt:

> JSON.stringify(subscription);

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

Vanaf Chrome 43 worden de eigenschappen die in het prototype zijn gedefinieerd, niet meer geserialiseerd. U ontvangt dan een leeg object.

> JSON.stringify(subscription);

{}

U moet uw eigen serialisatiemethode opgeven. U kunt bijvoorbeeld het volgende doen:

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

Schrijven naar alleen-lezen eigenschappen in de strikte modus zal een fout opleveren

Schrijven naar alleen-lezen eigenschappen zou een uitzondering moeten genereren wanneer u de strikte modus gebruikt. Neem bijvoorbeeld het volgende:

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

In Chrome 42 en ouder zou de functie nog steeds actief zijn en de uitvoering ervan in stilte voortzetten, hoewel isContentEditable niet zou zijn gewijzigd.

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

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

Vanaf Chrome 43 wordt er een uitzondering gegenereerd.

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

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

Ik heb een probleem, wat moet ik doen?

Volg de instructies of laat hieronder een reactie achter, dan praten we verder.

Ik heb een site gezien met een probleem, wat moet ik doen?

Goede vraag. De meeste problemen met websites worden veroorzaakt doordat een website ervoor heeft gekozen om Attribute Presence Detection uit te voeren met de getOwnProperty -methode. Dit gebeurt meestal wanneer een website-eigenaar alleen oudere WebKit-browsers gebruikt. Een ontwikkelaar kan een aantal dingen doen:

  • Meld een probleem met de getroffen site op onze (Chrome's) issue tracker
  • Meld een probleem op de WebKit-radar en verwijs naar https://bugs.webkit.org/show_bug.cgi?id=49739

Ik ben over het algemeen geïnteresseerd in het volgen van deze verandering