Zespół Chrome niedawno ogłosił, że przenosi właściwości DOM do łańcucha prototypów. Ta zmiana, wprowadzona w Chrome 43 (wersja beta z połowy kwietnia 2015 r.), sprawia, że Chrome jest bardziej zgodny z specyfikacją Web IDL i implementacjami w innych przeglądarkach, takich jak IE i Firefox. Edytuj: wyjaśnienie Starsze przeglądarki oparte na WebKit nie są obecnie zgodne ze specyfikacją, ale Safari już jest.
Nowe zachowanie ma wiele zalet. Oto one:
- Poprawia zgodność w internecie (IE i Firefox już to robią) dzięki zgodności ze specyfikacją.
- Umożliwia spójne i wydajne tworzenie metod get i set w przypadku każdego obiektu DOM.
- Zwiększa podatność na włamanie kodu programowania DOM. Na przykład możesz zaimplementować elementy polyfill, które umożliwiają skuteczne emulowanie 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 przeglądarka Chrome nie obsługuje, ale można ją zaimplementować za pomocą biblioteki. Jako twórca biblioteki możesz użyć funkcji prototype
w taki sposób, aby utworzyć wydajne rozwiązanie polyfill:
Object.defineProperty(HTMLDivElement.prototype, "isSuperContentEditable", {
get: function() { return true; },
set: function() { /* some logic to set it up */ },
});
Przed wprowadzeniem tej zmiany – ze względu na spójność z innymi właściwościami DOM w Chrome – należałoby utworzyć nową właściwość w każdym wystąpieniu, co w przypadku każdego HTMLDivElement
na stronie byłoby bardzo niewydajne.
Te zmiany są ważne dla spójności, wydajności i ujednolicania platformy internetowej, ale mogą powodować pewne problemy dla deweloperów. Jeśli polegasz na tym zachowaniu ze względu na zgodność starszych wersji Chrome i WebKit, sprawdź swoją witrynę i przeczytaj podsumowanie zmian poniżej.
Podsumowanie zmian
Użycie funkcji hasOwnProperty
na przykładzie obiektu DOM spowoduje teraz zwrócenie wartości false
.
Czasami deweloperzy używają hasOwnProperty
, aby sprawdzić, czy w obiekcie występuje dana właściwość. Zgodnie ze specyfikacją nie będzie to już działać, 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 jej lidze zwracano wartość true
.
> div = document.createElement("div");
> div.hasOwnProperty("isContentEditable");
true
Od wersji Chrome 43 zwraca on wartość false
.
> div = document.createElement("div");
> div.hasOwnProperty("isContentEditable");
false
Oznacza to, że jeśli chcesz sprawdzić, czy element isContentEditable
jest dostępny, musisz sprawdzić prototyp obiektu HTMLElement. Na przykład klasa HTMLDivElement
dziedziczy z klasy HTMLElement
, która definiuje właściwość isContentEditable
.
> HTMLElement.prototype.hasOwnProperty("isContentEditable");
true
Nie musisz używać aplikacji hasOwnProperty
. Zalecamy użycie znacznie prostszego operandu in
, ponieważ sprawdza on właściwość w całym łańcuchu prototypów.
if("isContentEditable" in div) {
// We have support!!
}
Obiekt.getOwnPropertyDescriptor w przypadku obiektu DOM nie będzie już zwracać opisu właściwości dla atrybutów
Jeśli Twoja witryna musi uzyskać opis właściwości dla atrybutu obiektu DOM, musisz teraz śledzić łańcuch prototypów.
Aby uzyskać opis obiektu w Chrome w wersji 42 lub starszej, wykonaj te czynności:
> Object.getOwnPropertyDescriptor(div, "isContentEditable");
Object {value: "", writable: true, enumerable: true, configurable: true}
W tym scenariuszu Chrome 43 i nowsze wersje zwracają undefined
.
> Object.getOwnPropertyDescriptor(div, "isContentEditable");
undefined
Oznacza to, że aby uzyskać opis właściwości isContentEditable
, musisz teraz postępować zgodnie z łańcuchem prototypów w taki sposób:
> Object.getOwnPropertyDescriptor(HTMLElement.prototype, "isContentEditable");
Object {get: function, set: function, enumerable: false, configurable: false}
Funkcja JSON.stringify nie będzie już serializować atrybutów DOM.
JSON.stringify
nie serializuje właściwości DOM, które znajdują się w prototypie. Może to na przykład wpływać na Twoją witrynę, jeśli próbujesz serializować obiekt, np. PushSubscription powiadomienia push.
W Chrome 42 i starszych działały te opcje:
> JSON.stringify(subscription);
{
"endpoint": "https://something",
"subscriptionId": "SomeID"
}
Od wersji 43 Chrome nie będzie serializować właściwości zdefiniowanych w prototypie, a zamiast tego zwróci pusty obiekt.
> JSON.stringify(subscription);
{}
Musisz podać własną metodę serializacji. Możesz na przykład wykonać te czynności:
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łaściwości tylko do odczytu w rygorystycznym trybie spowoduje błąd
Zapisywanie danych w właściwościach tylko do odczytu powinno wywołać wyjątek, gdy używasz trybu rygorystycznego. 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 42 i starszych funkcja ta była nadal wykonywana, ale isContentEditable
nie ulegał zmianie.
// Chrome 42 and earlier behavior
> foo();
false // isContentEditable
false // isContentEditable (after writing to read-only property)
Od wersji 43 Chrome będzie wyrzucać 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 z tymi wskazówkami lub zostaw komentarz poniżej.
Co mam zrobić, jeśli widzę problem z witryną?
Świetne pytanie. Większość problemów z witrynami wynika z tego, że witryna używa metody getOwnProperty
do wykrywania obecności atrybutów. Dzieje się tak głównie wtedy, gdy właściciel witryny kieruje reklamy tylko do starszych przeglądarek WebKit. Deweloperzy mogą zrobić kilka rzeczy:
- Prześlij zgłoszenie dotyczące problemu z witryną w naszym systemie śledzenia problemów (Chrome)
- Zgłoś problem w systemie śledzenia błędów WebKit i odwołaj się do https://bugs.webkit.org/show_bug.cgi?id=49739
Interesuje mnie ta zmiana
- Oryginalna usterka z 2010 r.: https://bugs.chromium.org/p/chromium/issues/detail?id=43394 – uwaga: zawiera większość prac.
- Sprawdzanie kodu po zatwierdzeniu