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ẽ di 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 vào giữa tháng 4 năm 2015) – giúp Chrome phù hợp hơn với Thông số kỹ thuật web IDL 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 Truy cập trực tuyến cũ hơn, hiện không tương thích với các thông số kỹ thuật, tuy nhiên Safari.

Hành vi mới này mang tính tích cực trên nhiều phương diện. 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 đã thực hiện việc 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 khi lập trình DOM. Ví dụ: tuỳ chọn này cho phép bạn triển khai các đoạn mã polyfill cho phép bạn 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 giúp ghi đè các hành vi thuộc tính DOM mặc định.

Ví dụ: bản đặc tả W3C giả định có 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 bạn vẫn có thể tạo "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, đương nhiên bạn nên sử dụng prototype như sau để tạo một đoạn mã 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ó sự thay đổi này – để đảm bảo tính nhất quán với các tài sản DOM khác trong Chrome, bạn sẽ phải tạo thuộc tính mới trong mọi trường hợp. Điều này sẽ 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à tiêu 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 dựa vào hành vi này do tính tương thích cũ giữa Chrome và WebM, chúng tôi khuyên bạn nên kiểm tra trang web của mình và xem bản tóm tắt các thay đổi ở bên dưới.

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

Giờ đây, việc sử dụng hasOwnProperty trên một thực thể Đối tượng DOM sẽ trả về false

Đôi khi, nhà phát triển sẽ sử dụng hasOwnProperty để kiểm tra sự hiện diện của một thuộc tính trên một đối tượng. Thuộc tính này sẽ không còn hoạt động 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 liệu có được xác định trên chuỗi đó hay không.

Trước và bao gồm Chrome 42, thao tác sau sẽ trả về true.

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

true

Từ Chrome 43 trở đi, lệnh này sẽ trả về false.

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

false

Điều này hiện có nghĩa là nếu muốn kiểm tra xem isContentEditable có hoạt động 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 thể sử dụng được 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ề phần 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 xem nội dung mô tả tài sản trong Chrome 42 trở xuống, bạn nên làm 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

Tức là để lấy được chỉ số mô tả thuộc tính cho thuộc tính isContentEditable, bạn cần tuân 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 còn 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ụ: việc 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, chẳng hạn như PushSubscription của Thông báo đẩy.

Chrome 42 trở xuống, các tính năng sau đây sẽ hoạt động:

> 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ụ như 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 ở chế độ nghiêm ngặt sẽ gây ra lỗi

Việc ghi vào các thuộc tính chỉ đọc sẽ tạo ra một ngoại lệ khi bạn đang sử dụng chế độ nghiêm ngặt. Ví dụ: hãy thực hiện như sau:

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

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

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

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

Bây giờ, từ Chrome 43 trở lên, hệ thống sẽ gửi một trường hợp ngoại lệ.

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

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

Tôi gặp sự cố, 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 và cùng trao đổi nhé.

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

Câu hỏi hay đó! Hầu hết vấn đề với các trang web đều dựa trên thực tế là trang web đã chọn 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 mục tiêu đến các trình duyệt Truy cập phiên bản Tin nhắn phiên bản cũ. Nhà phát triển có thể làm một số việc sau đây:

  • Gửi vấn đề về trang web bị ảnh hưởng qua công cụ theo dõi lỗi của chúng tôi (của Chrome)
  • Gửi sự cố trên radar ASan 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