プロトタイプ チェーンに DOM 属性を追加

Chrome チームは最近、DOM プロパティをプロトタイプ チェーンに移行することを発表しました。この変更は Chrome 43(2015 年 4 月中旬時点ではベータ版)で実装され、Chrome を Web IDL 仕様や IE や Firefox などの他のブラウザの実装に近づけています。編集: 明確化 古い WebKit ベースのブラウザは現在、仕様に対応していません。ただし、Safari は対応しています。

新しい動作には多くのメリットがあります。。

  • 仕様に準拠することで、ウェブ全体の互換性が向上します(IE と Firefox ではすでに対応しています)。
  • すべての DOM オブジェクトにゲッターとセッターを一貫して効率的に作成できます。
  • DOM プログラミングのハッキング可能性が増大します。たとえば、ポリフィルを実装することで、一部のブラウザや、デフォルトの DOM 属性の動作をオーバーライドする JavaScript ライブラリに欠落している機能を効率的にエミュレートできます。

たとえば、仮想の W3C 仕様に isSuperContentEditable という新しい機能が含まれていて、Chrome ブラウザに実装されていない場合でも、ライブラリで「ポリフィル」または機能をエミュレートできます。ライブラリ デベロッパーは、次のように prototype を使用して効率的なポリフィルを作成します。

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

この変更前は、Chrome の他の DOM プロパティとの整合性を確保するために、すべてのインスタンスで新しいプロパティを作成する必要がありました。これは、ページ上のすべての HTMLDivElement に対して行うと非常に非効率的でした。

これらの変更は、ウェブ プラットフォームの一貫性、パフォーマンス、標準化にとって重要ですが、デベロッパーに問題を引き起こす可能性があります。Chrome と WebKit の従来の互換性のためにこの動作に依存していた場合は、サイトを確認し、以下の変更の概要をご確認ください。

変更の概要

DOM オブジェクト インスタンスで hasOwnProperty を使用すると、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 オブジェクトのプロトタイプを確認する必要があります。たとえば、HTMLDivElementisContentEditable プロパティを定義する HTMLElement から継承します。

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

true

hasOwnProperty の使用に制限はありません。プロトタイプ チェーン全体でプロパティをチェックするため、はるかにシンプルな in オペランドを使用することをおすすめします。

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

DOM オブジェクト インスタンスの Object.getOwnPropertyDescriptor が属性のプロパティ記述子を返さなくなる

サイトが 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 プロパティをシリアル化しません。たとえば、プッシュ通知の 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);
}

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 レーダーで問題を報告し、https://bugs.webkit.org/show_bug.cgi?id=49739 を参照します。

一般に、この変更のフォローに関心がある