Atrybuty DOM są teraz w łańcuchu prototypu

Zespół Chrome niedawno ogłosił, że przenosimy właściwości DOM do łańcucha prototypów. Ta zmiana, wdrożona w Chrome 43 (wersja beta od połowy kwietnia 2015 r.), sprawi, że Chrome będzie bardziej zgodny ze Specyfikacją Web IDL i innymi implementacjami przeglądarek, takich jak IE czy Firefox. Zmiana: doprecyzowano Starsze przeglądarki oparte na silniku WebKit nie są obecnie zgodne ze specyfikacją, ale obecnie Safari już tak.

Nowe zachowanie jest pod wieloma względami korzystne. Oto one:

  • Zwiększa zgodność ze specyfikacją w internecie (ma to już zastosowanie w przeglądarce IE i Firefox).
  • Umożliwia spójne i efektywne tworzenie metod pobierających/seterów w przypadku każdego obiektu DOM.
  • Zwiększa możliwość hakowania programowania DOM. Umożliwia na przykład wdrożenie kodu polyfill, który umożliwi efektywną emulację funkcji niedostępnych w niektórych przeglądarkach i bibliotekach JavaScript, które zastępują domyślne zachowania atrybutów DOM.

Na przykład hipotetyczna specyfikacja W3C zawiera nową funkcję o nazwie isSuperContentEditable, której nie implementuje przeglądarka Chrome. Istnieje jednak możliwość „polyfill” lub emulacji tej funkcji za pomocą biblioteki. Deweloper biblioteki powinien oczywiście użyć parametru prototype w ten sposób, aby utworzyć skuteczne kod polyfill:

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

Przed tą zmianą, aby zachować spójność z innymi właściwościami DOM w Chrome, trzeba było w każdym przypadku tworzyć nową właściwość, co w przypadku każdego elementu HTMLDivElement na stronie byłoby bardzo nieefektywne.

Te zmiany są istotne dla zachowania spójności, wydajności i standaryzacji platformy internetowej, ale mogą powodować pewne problemy deweloperom. Jeśli to działanie wynikało z Twojej zgodności ze starszą wersją Chrome i WebKit, zachęcamy do sprawdzenia swojej witryny i zapoznania się z podsumowaniem zmian poniżej.

Podsumowanie zmian

Użycie polecenia hasOwnProperty w instancji obiektu DOM będzie teraz zwracać wartość false

Czasami deweloperzy używają elementu hasOwnProperty, aby sprawdzić, czy w obiekcie występuje właściwość. Nie będzie to już działać zgodnie ze specyfikacją, ponieważ atrybuty DOM są teraz częścią łańcucha prototypów, a hasOwnProperty sprawdza tylko bieżące obiekty, aby sprawdzić, czy są w nich zdefiniowane.

Przed wersją Chrome 42 i w przypadku Chrome 42 funkcja poniżej zwracała wartość true.

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

true

Od wersji Chrome 43 zwraca wartość false.

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

false

Oznacza to, że jeśli chcesz sprawdzić, czy element isContentEditable jest dostępny w elemencie, sprawdź prototyp w obiekcie HTMLElement. Na przykład HTMLDivElement dziedziczy właściwość HTMLElement, która określa właściwość isContentEditable.

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

true

Nie możesz korzystać z hasOwnProperty. Zalecamy użycie znacznie prostszego operandu in, ponieważ pozwoli to sprawdzić właściwość w całym łańcuchu prototypu.

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

Metoda Object.getPropertyDescriptor w instancji obiektu DOM nie będzie już zwracać deskryptora właściwości w przypadku atrybutów

Jeśli Twoja witryna musi uzyskać deskryptor właściwości dla atrybutu obiektu DOM, musisz teraz śledzić łańcuch prototypu.

Aby uzyskać opis właściwości w Chrome 42 i starszych wersjach:

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

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

W takiej sytuacji Chrome od wersji 43 zwróci wartość undefined.

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

undefined

Oznacza to, że aby teraz uzyskać deskryptor właściwości isContentEditable, musisz prześledzić łańcuch prototypu w ten sposób:

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

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

JSON.stringify nie będzie już serializować atrybutów DOM

JSON.stringify nie szereguje właściwości DOM, które znajdują się w prototypie. Może to na przykład mieć wpływ na Twoją witrynę, jeśli próbujesz zserializować obiekt, taki jak PushSubscription w powiadomieniach push.

W Chrome 42 i starszych wersjach zadziałałoby to w następujący sposób:

> JSON.stringify(subscription);

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

Od wersji 43 Chrome nie zserializuje właściwości, które są zdefiniowane w prototypie, a Ty otrzymasz pusty obiekt.

> JSON.stringify(subscription);

{}

Musisz podać własną metodę serializacji, na przykład:

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

Zapisywanie w usługach tylko do odczytu w trybie ścisłym spowoduje zgłoszenie błędu

Zapisywanie w usługach tylko do odczytu powinno zgłaszać wyjątek w przypadku korzystania z trybu ścisłego. Na przykład:

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

W Chrome w wersji 42 i starszych funkcja ta byłaby kontynuowana i cichutnie kontynuowana, chociaż isContentEditable nie zmieniłby się.

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

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

Od wersji Chrome 43 zostanie zgłoszony wyjątek.

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

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

Mam problem, co mam zrobić?

Postępuj zgodnie ze wskazówkami lub napisz komentarz poniżej i do dzieła.

Na stronie jest problem. Co mam zrobić?

Świetne pytanie. Większość problemów z witrynami wynika z faktu, że witryna wykrywa obecność atrybutów za pomocą metody getOwnProperty. Następuje to przeważnie wtedy, gdy właściciel witryny kieruje reklamy tylko na starsze przeglądarki WebKit. Deweloper może wykonać kilka czynności:

  • Zgłoś problem dotyczący witryny, korzystając z naszego narzędzia Chrome do śledzenia błędów.
  • Zgłoś problem, korzystając z radaru WebKit, dodając odwołanie na stronie https://bugs.webkit.org/show_bug.cgi?id=49739

Interesuje mnie śledzenie tej zmiany