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

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

新しい行動はさまざまな点で好ましいものです。つまり、

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

たとえば、架空の 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 Object インスタンスで hasOwnProperty を使用すると false が返されるようになりました

デベロッパーが hasOwnProperty を使用して、オブジェクトのプロパティの有無をチェックする場合もあります。これは、DOM 属性はプロトタイプ チェーンの一部になり、hasOwnProperty は現在のオブジェクトを調べて定義されているかどうかを確認するだけであるため、仕様どおりに機能しなくなります。

Chrome 42 より前(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 は、isContentEditable プロパティを定義する 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);

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 ブラウザのみをターゲットにしている場合に該当します。デベロッパーは、次のようなことを行えます。

  • Google の(Chrome)の Issue Tracker で影響を受けるサイトに関する問題を報告してください
  • WebKit レーダーで問題を報告し、https://bugs.webkit.org/show_bug.cgi?id=49739 を参照してください

概して、この変更に関心を持っている