DOM-Attribute jetzt in der Prototypkette

Das Chrome-Team hat vor Kurzem angekündigt, dass wir DOM-Properties in die Prototyp-Kette verschieben. Diese Änderung, die in Chrome 43 (Betaversion, Stand Mitte April 2015) implementiert wurde, bringt Chrome mehr in Einklang mit der Web IDL-Spezifikation und der Implementierung anderer Browser wie IE und Firefox. Änderung: Klarstellung: Ältere WebKit-basierte Browser sind derzeit nicht mit der Spezifikation kompatibel, Safari ist es aber.

Das neue Verhalten hat viele Vorteile. Die DSGVO hat folgenden Zweck:

  • Verbesserte Kompatibilität im Web (IE und Firefox bieten dies bereits) durch Einhaltung der Spezifikation.
  • Ermöglicht es, für jedes DOM-Objekt einheitlich und effizient Getter/Setter zu erstellen.
  • Erhöht die Hackbarkeit der DOM-Programmierung. So können Sie beispielsweise Polyfills implementieren, mit denen Sie Funktionen, die in einigen Browsern fehlen, effizient emulieren, und JavaScript-Bibliotheken, die das Standardverhalten von DOM-Attributen überschreiben.

Angenommen, eine hypothetische W3C-Spezifikation enthält eine neue Funktion namens isSuperContentEditable, die im Chrome-Browser nicht implementiert ist. Es ist jedoch möglich, die Funktion mit einer Bibliothek zu „polyfillen“ oder zu emulieren. Als Bibliotheksentwickler möchten Sie natürlich die prototype so verwenden, um eine effiziente polyfill zu erstellen:

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

Vor dieser Änderung mussten Sie die neue Property aus Gründen der Konsistenz mit anderen DOM-Properties in Chrome in jeder Instanz erstellen. Das wäre für jede HTMLDivElement auf der Seite sehr ineffizient gewesen.

Diese Änderungen sind wichtig für Konsistenz, Leistung und Standardisierung der Webplattform, können aber einige Probleme für Entwickler verursachen. Wenn Sie sich auf dieses Verhalten verlassen haben, weil Chrome und WebKit bisher kompatibel waren, sollten Sie Ihre Website prüfen und sich die Zusammenfassung der Änderungen unten ansehen.

Zusammenfassung der Änderungen

Wenn hasOwnProperty auf eine DOM-Objektinstanz angewendet wird, wird jetzt false zurückgegeben.

Manchmal verwenden Entwickler hasOwnProperty, um zu prüfen, ob eine Property bei einem Objekt vorhanden ist. Das funktioniert nicht mehr gemäß der Spezifikation, da DOM-Attribute jetzt Teil der Prototypkette sind und hasOwnProperty nur die aktuellen Objekte prüft, um festzustellen, ob das Attribut dort definiert ist.

In Chrome 42 und niedriger wurde für die folgende Anfrage true zurückgegeben.

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

true

Ab Chrome 43 wird false zurückgegeben.

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

false

Wenn Sie also prüfen möchten, ob isContentEditable für das Element verfügbar ist, müssen Sie den Prototyp im HTMLElement-Objekt prüfen. Beispiel: HTMLDivElement wird von HTMLElement abgeleitet, das das Attribut isContentEditable definiert.

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

true

Sie sind nicht verpflichtet, hasOwnProperty zu verwenden. Wir empfehlen, den viel einfacheren Operanden in zu verwenden, da damit die Property in der gesamten Prototyp-Kette geprüft wird.

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

Object.getOwnPropertyDescriptor für DOM-Objektinstanz gibt keinen Property-Descriptor für Attribute mehr zurück

Wenn Ihre Website den Property-Descriptor für ein Attribut eines DOM-Objekts abrufen muss, müssen Sie jetzt der Prototyp-Kette folgen.

So haben Sie in Chrome 42 und niedriger die Property-Beschreibung abgerufen:

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

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

Ab Chrome 43 wird in diesem Szenario undefined zurückgegeben.

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

undefined

Wenn Sie also den Property-Descriptor für die Property isContentEditable abrufen möchten, müssen Sie die Prototyp-Kette so durchlaufen:

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

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

DOM-Attribute werden nicht mehr von JSON.stringify serialisiert

JSON.stringify serialisiert keine DOM-Attribute, die sich im Prototyp befinden. Das kann sich beispielsweise auf Ihre Website auswirken, wenn Sie versuchen, ein Objekt wie die PushSubscription von Push-Benachrichtigungen zu serialisieren.

In Chrome 42 und niedriger funktionierte Folgendes:

> JSON.stringify(subscription);

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

Ab Chrome 43 werden die im Prototyp definierten Eigenschaften nicht mehr serialisiert und es wird ein leeres Objekt zurückgegeben.

> JSON.stringify(subscription);

{}

Sie müssen Ihre eigene Serializationsmethode bereitstellen. Sie können beispielsweise Folgendes tun:

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

Wenn im strengen Modus in read-only-Properties geschrieben wird, wird ein Fehler ausgegeben.

Wenn Sie im strengen Modus schreibgeschützte Properties schreiben, sollte eine Ausnahme ausgelöst werden. Beispiel:

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

In Chrome 42 und niedrigeren Versionen würde die Funktion fortgesetzt und im Hintergrund ausgeführt, auch wenn isContentEditable nicht geändert wurde.

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

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

In Chrome 43 und höher wird nun eine Ausnahme ausgelöst.

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

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

Ich habe ein Problem. Was soll ich tun?

Folge der Anleitung oder hinterlasse unten einen Kommentar.

Ich habe eine Website mit einem Problem gefunden. Was soll ich tun?

Gute Frage. Die meisten Probleme mit Websites sind darauf zurückzuführen, dass die Erkennung der Attributenpräsenz mit der Methode getOwnProperty ausgewählt wurde. Dies geschieht in der Regel, wenn ein Websiteinhaber nur ältere WebKit-Browser anvisiert hat. Entwickler haben dabei verschiedene Möglichkeiten:

  • Melden Sie das Problem mit der betroffenen Website in unserem Chrome-Problem-Tracker.
  • Melden Sie ein Problem im WebKit-Radar und verweisen Sie auf https://bugs.webkit.org/show_bug.cgi?id=49739.

Ich bin grundsätzlich an dieser Änderung interessiert.