מאפייני DOM נמצאים עכשיו בשרשרת אב הטיפוס

צוות Chrome הכריז לאחרונה שאנחנו מעבירים את נכסי DOM לשרשרת אב הטיפוס. השינוי הזה, שהוטמע ב-Chrome 43 - (בטא החל מאמצע אפריל 2015) - משפר את Chrome ביחס למפרט Web IDL ולהטמעות של דפדפנים אחרים, כמו IE ו-Firefox. עריכה: הבהרה דפדפנים ישנים יותר המבוססים על WebKit לא תואמים כרגע למפרט, אבל עכשיו Safari כן כן.

ההתנהגות החדשה היא חיובית מבחינות רבות. התיוג האוטומטי:

  • משפר את התאימות באינטרנט (IE ו-Firefox כבר עושים זאת) באמצעות תאימות למפרט.
  • מאפשר לכם ליצור getter/setter באופן עקבי ויעיל בכל אובייקט DOM.
  • מגדיל את יכולת הפריצה לתכנות DOM. לדוגמה, הוא יאפשר לך להטמיע רכיבי Polyfill שיכולים לחקות ביעילות פונקציונליות שחסרה בחלק מהדפדפנים ובספריות JavaScript שמבטלות את התנהגויות ברירת המחדל של מאפייני DOM.

לדוגמה, מפרט היפותטי של W3C כולל פונקציונליות חדשה שנקראת isSuperContentEditable ודפדפן Chrome לא מטמיע אותה, אבל ניתן לבצע "polyfill" או לבצע אמולציה של התכונה באמצעות ספרייה. כמפתח הספרייה, תרצה באופן טבעי להשתמש ב-prototype באופן הבא כדי ליצור Polyfill יעיל:

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

לפני השינוי הזה – כדי לשמור על עקביות עם מאפייני DOM אחרים ב-Chrome – הייתם צריכים ליצור את המאפיין החדש בכל מכונה, וכך כל HTMLDivElement בדף לא יהיה יעיל מאוד.

השינויים האלה חשובים לעקביות, לביצועים ולסטנדרטיזציה של פלטפורמת האינטרנט, אבל הם יכולים לגרום לבעיות מסוימות למפתחים. אם הסתמכת על ההתנהגות הזו בגלל תאימות מדור קודם בין Chrome ל-WebKit, אנחנו ממליצים לך לבדוק את האתר ולראות את סיכום השינויים בהמשך.

סיכום השינויים

שימוש ב-hasOwnProperty במופע של DOM Object יחזיר עכשיו את הערך false

לפעמים מפתחים משתמשים ב-hasOwnProperty כדי לבדוק אם קיים נכס באובייקט. הפעולה הזו לא תפעל יותר לפי המפרט, כי מאפייני DOM הם עכשיו חלק משרשרת אב הטיפוס ו-hasOwnProperty בודקת רק את האובייקטים הנוכחיים כדי לראות אם הם מוגדרים בה.

לפני ואחרי Chrome 42, הערך הבא יחזיר true.

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

true

ב-Chrome 43 ואילך היא תחזיר false.

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

false

המשמעות היא שעכשיו, כדי לוודא ש-isContentEditable זמין ברכיב, עליך לבדוק את אב הטיפוס באובייקט HTMLElement. לדוגמה, הנכס HTMLDivElement מקבל בירושה מ-HTMLElement, שמגדיר את הנכס isContentEditable.

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

true

עדיין לא החלטת להשתמש ב-hasOwnProperty. אנחנו ממליצים להשתמש באופרנד in פשוט יותר, כי הוא יבדוק את המאפיין על כל שרשרת אב הטיפוס.

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

Object.getOwnPropertyDescriptor במופע של אובייקט DOM לא יחזיר יותר מתאר מאפיין עבור Attributes

אם האתר שלכם צריך לקבל את מתאר המאפיין עבור מאפיין באובייקט DOM, תצטרכו לעקוב אחר שרשרת האב טיפוס.

אם רוצים לקבל את תיאור המאפיין ב-Chrome 42 ומטה, צריך לבצע את הפעולות הבאות:

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

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

Chrome 43 ואילך יחזיר undefined בתרחיש הזה.

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

undefined

כלומר, כדי לקבל עכשיו את מתאר המאפיין עבור הנכס isContentEditable, יש לפעול לפי שרשרת האב טיפוס באופן הבא:

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

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

לא יתבצע יותר ארגון של מאפייני DOM בסדרה JSON.stringify

JSON.stringify לא מבצע סריאליזציה של מאפייני ה-DOM שנמצאים באב הטיפוס. לדוגמה, פעולה זו עשויה להשפיע על האתר שלך אם אתה מנסה לסדר אובייקט בסדרה, כמו PushSubscription של התראה.

Chrome מגרסה 42 ומטה:

> JSON.stringify(subscription);

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

Chrome 43 ואילך לא יבצע סריאליזציה של המאפיינים המוגדרים באב הטיפוס ותוחזר לכם אובייקט ריק.

> JSON.stringify(subscription);

{}

תצטרכו לספק שיטת עריכה בסדרה משלכם. לדוגמה, אפשר לבצע את הפעולות הבאות:

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

כתיבה לנכסי קריאה בלבד במצב strict תגרום לשגיאה

כתיבה לנכסים לקריאה בלבד אמורה לגרום לחריגה בעת שימוש במצב strict. לדוגמה:

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

Chrome בגרסה 42 ומטה הפונקציה הייתה ממשיכה לבצע את הפונקציה במצב שקט, למרות שהפונקציה isContentEditable לא הייתה משתנה.

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

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

ב-Chrome מגרסה 43 ואילך, תתקבל התראה חריגה.

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

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

נתקלתי בבעיה, מה עליי לעשות?

יש לפעול לפי ההנחיות, או להשאיר תגובה למטה כדי שנדבר.

ראיתי אתר עם בעיה. מה עליי לעשות?

שאלה מצוינת. רוב הבעיות באתרים יתבססו על העובדה שבאתר מסוים נעשה שימוש בזיהוי נוכחות של מאפיינים באמצעות השיטה getOwnProperty. בדרך כלל הבדיקה הזו מתבצעת כשבעל האתר טירגט רק דפדפני WebKit ישנים יותר. יש כמה פעולות שמפתח יכול לעשות:

  • לדווח על בעיה באתר המושפע באמצעות הכלי למעקב אחר בעיות (של Chrome)
  • דיווח על בעיה ב-WebKit radar וציון https://bugs.webkit.org/show_bug.cgi?id=49739

באופן כללי אני מעוניין לבצע את השינוי הזה