ویژگی های DOM اکنون در زنجیره نمونه اولیه

تیم Chrome اخیراً اعلام کرد که ما در حال انتقال ویژگی‌های DOM به زنجیره اولیه هستیم . این تغییر که در Chrome 43 پیاده‌سازی شده است - (بتا از اواسط آوریل 2015) - Chrome را با Web IDL Spec و سایر پیاده‌سازی‌های مرورگرها مانند IE و Firefox مطابقت می‌دهد. ویرایش: روشن شده مرورگرهای قدیمی مبتنی بر WebKit، در حال حاضر با مشخصات سازگار نیستند، اما Safari اکنون سازگار است.

رفتار جدید از بسیاری جهات مثبت است. آی تی:

  • سازگاری در سراسر وب را بهبود می بخشد (IE و فایرفاکس قبلاً این کار را انجام می دهند) از طریق مطابقت با مشخصات.
  • به شما امکان می دهد به طور مداوم و کارآمد بر روی هر شیء DOM، گیرنده/ تنظیم کننده ایجاد کنید.
  • قابلیت هک شدن برنامه نویسی DOM را افزایش می دهد. به عنوان مثال، به شما امکان می‌دهد که polyfills را پیاده‌سازی کنید که به شما امکان می‌دهد به طور موثر عملکردهایی را که در برخی از مرورگرها و کتابخانه‌های جاوا اسکریپت که رفتارهای ویژگی DOM پیش‌فرض را نادیده می‌گیرند، شبیه‌سازی کنید.

به عنوان مثال، یک مشخصات فرضی W3C شامل برخی عملکردهای جدید به نام isSuperContentEditable است و مرورگر کروم آن را پیاده‌سازی نمی‌کند، اما می‌توان این ویژگی را با یک کتابخانه «polyfill» یا شبیه‌سازی کرد. به عنوان توسعه‌دهنده کتابخانه، طبیعتاً می‌خواهید از prototype به صورت زیر برای ایجاد یک polyfill کارآمد استفاده کنید:

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

قبل از این تغییر - برای سازگاری با سایر ویژگی‌های DOM در کروم - باید ویژگی جدید را در هر نمونه ایجاد می‌کردید، که برای هر 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 Object Instance دیگر توصیفگر خاصیت را برای ویژگی ها بر نمی گرداند.

اگر سایت شما نیاز به دریافت توصیفگر ویژگی برای یک ویژگی در یک شی 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}

JSON.stringify دیگر ویژگی های DOM را سریالی نمی کند

JSON.stringify ویژگی های DOM را که در نمونه اولیه هستند سریال نمی کند. برای مثال، اگر می‌خواهید شی‌ای مانند Push Notification's 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);

نوشتن در ویژگی های فقط خواندنی در حالت سخت باعث ایجاد خطا می شود

زمانی که از حالت سخت استفاده می کنید، قرار است نوشتن در ویژگی های فقط خواندنی یک استثنا ایجاد کند. برای مثال موارد زیر را در نظر بگیرید:

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

کروم 42 و قبل از آن، این عملکرد ادامه می‌یابد و بی‌صدا به اجرای عملکرد ادامه می‌دهد، اگرچه isContentEditable تغییر نمی‌کند.

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

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

اکنون در کروم 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 و مرجع https://bugs.webkit.org/show_bug.cgi?id=49739 ثبت کنید

من به طور کلی علاقه مند به دنبال کردن این تغییر هستم