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
- Oryginalny błąd z 2010 roku: https://bugs.chromium.org/p/chromium/issues/detail?id=43394. Uwaga: w większości pracy zajmuje się nim.
- Weryfikacja kodu w ramach zatwierdzenia