Thuộc tính DOM hiện đã có trên chuỗi nguyên mẫu

Gần đây, nhóm Chrome đã thông báo rằng chúng tôi sẽ chuyển các thuộc tính DOM sang chuỗi nguyên mẫu. Thay đổi này, được triển khai trong Chrome 43 – (Bản thử nghiệm từ giữa tháng 4 năm 2015) – giúp Chrome phù hợp hơn với Thông số kỹ thuật IDL web và cách triển khai của các trình duyệt khác, chẳng hạn như IE và Firefox. Chỉnh sửa: làm rõ   Các trình duyệt dựa trên WebKit cũ hiện không tương thích với thông số kỹ thuật, tuy nhiên Safari hiện đã tương thích.

Hành vi mới này mang lại nhiều lợi ích. Tính năng tự động gắn thẻ:

  • Cải thiện khả năng tương thích trên web (IE và Firefox đã làm điều này) thông qua việc tuân thủ thông số kỹ thuật.
  • Cho phép bạn tạo phương thức getter/setter một cách nhất quán và hiệu quả trên mọi Đối tượng DOM.
  • Tăng khả năng xâm nhập của hoạt động lập trình DOM. Ví dụ: bạn có thể triển khai các polyfill để mô phỏng hiệu quả chức năng bị thiếu trong một số trình duyệt và thư viện JavaScript ghi đè hành vi thuộc tính DOM mặc định.

Ví dụ: một thông số kỹ thuật W3C giả định bao gồm một số chức năng mới có tên là isSuperContentEditable và Trình duyệt Chrome không triển khai chức năng này, nhưng có thể "polyfill" hoặc mô phỏng tính năng này bằng một thư viện. Là nhà phát triển thư viện, bạn sẽ muốn sử dụng prototype như sau để tạo một polyfill hiệu quả:

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

Trước khi có thay đổi này – để đảm bảo tính nhất quán với các thuộc tính DOM khác trong Chrome – bạn phải tạo thuộc tính mới trên mọi thực thể, điều này sẽ rất không hiệu quả đối với mọi HTMLDivElement trên trang.

Những thay đổi này rất quan trọng đối với tính nhất quán, hiệu suất và việc chuẩn hoá nền tảng web, nhưng cũng có thể gây ra một số vấn đề cho nhà phát triển. Nếu bạn đang dựa vào hành vi này do khả năng tương thích cũ giữa Chrome và WebKit, bạn nên kiểm tra trang web của mình và xem phần tóm tắt các thay đổi bên dưới.

Tóm tắt các thay đổi

Việc sử dụng hasOwnProperty trên một thực thể Đối tượng DOM hiện sẽ trả về false

Đôi khi, nhà phát triển sẽ sử dụng hasOwnProperty để kiểm tra xem một thuộc tính có trên đối tượng hay không. Phương thức này sẽ không còn hoạt động như theo thông số kỹ thuật vì các thuộc tính DOM hiện là một phần của chuỗi nguyên mẫu và hasOwnProperty chỉ kiểm tra các đối tượng hiện tại để xem thuộc tính này có được xác định trên đó hay không.

Trước và bao gồm cả Chrome 42, mã sau đây sẽ trả về true.

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

true

Trong Chrome 43 trở lên, hàm này sẽ trả về false.

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

false

Điều này có nghĩa là nếu muốn kiểm tra xem isContentEditable có trên phần tử hay không, bạn sẽ phải kiểm tra nguyên mẫu trên đối tượng HTMLElement. Ví dụ: HTMLDivElement kế thừa từ HTMLElement xác định thuộc tính isContentEditable.

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

true

Bạn không bị ràng buộc phải sử dụng hasOwnProperty. Bạn nên sử dụng toán hạng in đơn giản hơn nhiều vì toán hạng này sẽ kiểm tra thuộc tính trên toàn bộ chuỗi nguyên mẫu.

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

Object.getOwnPropertyDescriptor trên Thực thể đối tượng DOM sẽ không còn trả về chỉ số mô tả thuộc tính cho Thuộc tính

Nếu trang web của bạn cần lấy chỉ số mô tả thuộc tính cho một thuộc tính trên Đối tượng DOM, thì giờ đây, bạn cần tuân theo chuỗi nguyên mẫu.

Nếu muốn lấy nội dung mô tả tài sản trong Chrome 42 trở xuống, bạn sẽ thực hiện như sau:

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

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

Chrome 43 trở lên sẽ trả về undefined trong trường hợp này.

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

undefined

Điều này có nghĩa là để lấy chỉ số mô tả thuộc tính cho thuộc tính isContentEditable, bạn cần làm theo chuỗi nguyên mẫu như sau:

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

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

JSON.stringify sẽ không chuyển đổi tuần tự các Thuộc tính DOM nữa

JSON.stringify không chuyển đổi tuần tự các thuộc tính DOM trên nguyên mẫu. Ví dụ: điều này có thể ảnh hưởng đến trang web của bạn nếu bạn đang cố gắng chuyển đổi tuần tự một đối tượng như PushSubscription của Thông báo đẩy.

Đối với Chrome 42 trở xuống, bạn có thể làm như sau:

> JSON.stringify(subscription);

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

Chrome 43 trở lên sẽ không chuyển đổi tuần tự các thuộc tính được xác định trên nguyên mẫu và bạn sẽ được trả về một đối tượng trống.

> JSON.stringify(subscription);

{}

Bạn sẽ phải cung cấp phương thức chuyển đổi tuần tự của riêng mình, ví dụ: bạn có thể làm như sau:

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

Việc ghi vào các thuộc tính chỉ có thể đọc ở chế độ nghiêm ngặt sẽ gây ra lỗi

Việc ghi vào các thuộc tính chỉ có thể đọc sẽ gửi một ngoại lệ khi bạn đang sử dụng chế độ nghiêm ngặt. Ví dụ: hãy xem xét những nội dung sau:

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

Trong Chrome 42 trở xuống, hàm này sẽ tiếp tục và âm thầm thực thi hàm, mặc dù isContentEditable sẽ không thay đổi.

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

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

Giờ đây, trong Chrome 43 trở lên, một ngoại lệ sẽ được gửi.

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

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

Tôi gặp vấn đề, tôi nên làm gì?

Hãy làm theo hướng dẫn hoặc để lại bình luận bên dưới để chúng ta trao đổi thêm.

Tôi thấy một trang web có vấn đề, tôi nên làm gì?

Câu hỏi hay đó! Hầu hết các vấn đề về trang web sẽ dựa trên việc trang web đã chọn thực hiện tính năng phát hiện sự hiện diện của thuộc tính bằng phương thức getOwnProperty. Việc này chủ yếu được thực hiện khi chủ sở hữu trang web chỉ nhắm đến các trình duyệt WebKit cũ. Nhà phát triển có thể làm một số việc sau:

  • Gửi vấn đề về trang web bị ảnh hưởng trên công cụ theo dõi lỗi của chúng tôi (Chrome)
  • Gửi vấn đề trên radar WebKit và tham khảo https://bugs.webkit.org/show_bug.cgi?id=49739

Tôi thường quan tâm đến việc theo dõi thay đổi này