DOM-attributen nu in de prototypeketen

Het Chrome-team heeft onlangs aangekondigd dat we DOM-eigendommen naar de prototypeketen verplaatsen . Deze wijziging, geïmplementeerd in Chrome 43 - (bèta vanaf medio april 2015) - brengt Chrome meer in lijn met de Web IDL Spec en implementaties van andere browsers, zoals IE en Firefox. Bewerken: verduidelijkt. Oudere op 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 internet (IE en Firefox doen dit al) door te voldoen aan de specificaties.
  • Hiermee kunt u op consistente en efficiënte wijze getters/setters maken voor elk DOM-object.
  • Verhoogt de hackbaarheid van DOM-programmering. U kunt er bijvoorbeeld polyfills mee implementeren waarmee u op efficiënte wijze functionaliteit kunt emuleren die in sommige browsers ontbreekt, en JavaScript-bibliotheken die het standaardgedrag van DOM-attributen overschrijven.

Een hypothetische W3C-specificatie bevat bijvoorbeeld een nieuwe functionaliteit genaamd isSuperContentEditable en de Chrome-browser implementeert deze niet, maar het is mogelijk om de functie te "polyfillen" of te emuleren met een bibliotheek. Als bibliotheekontwikkelaar wilt u het prototype uiteraard als volgt 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 had u - voor consistentie met andere DOM-eigenschappen in Chrome - de nieuwe eigenschap voor elke instantie moeten maken, wat voor elk HTMLDivElement op de pagina zeer inefficiënt zou zijn.

Deze veranderingen zijn belangrijk voor de consistentie, prestaties en standaardisatie van het webplatform, maar kunnen voor ontwikkelaars enkele problemen veroorzaken. 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 de wijzigingen

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

Soms gebruiken ontwikkelaars hasOwnProperty om te controleren op de aanwezigheid van een eigenschap op een object. Dit werkt niet langer 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 zijn gedefinieerd.

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

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

true

Vanaf Chrome 43 retourneert het false .

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

false

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

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

true

U bent niet gebonden aan het gebruik van hasOwnProperty . We raden aan om de veel eenvoudigere in operand te gebruiken, omdat hiermee de eigenschappen van de gehele prototypeketen worden gecontroleerd.

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

Object.getOwnPropertyDescriptor op DOM Object Instance retourneert niet langer een eigenschapsdescriptor voor attributen

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

Als u de eigendomsbeschrijving in Chrome 42 en eerder had willen zien, had u het volgende gedaan:

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

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

Chrome 43 en hoger zal in dit scenario undefined terugkeren.

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

undefined

Dit betekent dat u, om nu de eigenschapsdescriptor voor de eigenschap isContentEditable te verkrijgen, de prototypeketen als volgt moet volgen:

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

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

JSON.stringify zal DOM-kenmerken niet langer serialiseren

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

Chrome 42 en eerder zou het volgende hebben gewerkt:

> JSON.stringify(subscription);

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

Chrome 43 en hoger serialiseert de eigenschappen die op het prototype zijn gedefinieerd niet en u krijgt een leeg object terug.

> 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 levert een fout op

Schrijven naar alleen-lezen-eigenschappen zou een uitzondering moeten opleveren als 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);
}

Chrome 42 en eerder zou de functie zijn voortgezet en de functie stilletjes hebben uitgevoerd, hoewel isContentEditable niet zou zijn gewijzigd.

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

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

In Chrome 43 en hoger zal er nu een uitzondering optreden.

// 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 richtlijnen of laat hieronder een reactie achter en laten we praten.

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

Grote vraag. De meeste problemen met sites zijn gebaseerd op het feit dat een site ervoor heeft gekozen om aanwezigheidsdetectie van kenmerken uit te voeren met de getOwnProperty -methode. Dit wordt meestal gedaan wanneer een site-eigenaar zich alleen op oudere WebKit-browsers heeft gericht. Er zijn een aantal dingen die een ontwikkelaar kan doen:

  • Dien een probleem in over de getroffen site via onze issuetracker (Chrome).
  • Dien een probleem in op de WebKit-radar en raadpleeg https://bugs.webkit.org/show_bug.cgi?id=49739

Over het algemeen ben ik geïnteresseerd in het volgen van deze verandering