1. ホーム
  2. javascript

[解決済み] すでにインスタンス化されているJavaScriptオブジェクトのプロトタイプを設定するには?

2022-10-26 02:40:45

質問

例えば、以下のようなオブジェクトがあるとします。 foo をJavaScriptのコードに書いたとします。 foo は複雑なオブジェクトで、どこか他の場所で生成されています。 のプロトタイプを変更するにはどうしたらよいでしょうか? foo オブジェクトのプロトタイプを変更するにはどうしたらよいでしょうか?

私の動機は、.NETからJavaScriptのリテラルにシリアル化されたオブジェクトに適切なプロトタイプを設定することです。

私がASP.NETページ内で次のJavaScriptコードを書いたとします。

var foo = <%=MyData %>;

仮に MyData は、.NET の JavaScriptSerializer の上で Dictionary<string,string> オブジェクトを作成します。

実行時には以下のようになる。

var foo = [{"A":"1","B":"2"},{"X":"7","Y":"8"}];

ご覧のように foo はオブジェクトの配列になります。を初期化できるようにしたい。 foo を適切なプロトタイプで初期化できるようにしたい。私は ではなく を修正したいのです。 Object.prototypeArray.prototype . どうすればいいのでしょうか?

どのように解決するのですか?

更新してください。 ES6で指定されるようになった Object.setPrototypeOf(オブジェクト, プロトタイプ)

.

2012年2月編集:以下の回答は、もはや正確ではありません。 プロト は ECMAScript 6 に "normative optional" として追加されました。これは、実装する必要はないが、実装する場合は与えられたルールのセットに従わなければならないことを意味します。これは現在未解決ですが、少なくとも公式に JavaScript の仕様の一部となる予定です。

この質問は表面的に見えるよりもずっと複雑で、Javascript の内部に関する知識に関して、ほとんどの人の給与水準を越えています。

その prototype プロパティは、そのオブジェクトの新しい子オブジェクトを作成するときに使用されます。これを変更してもオブジェクト自体には反映されず、むしろそのオブジェクトが他のオブジェクトのコンストラクタとして使用されるときに反映され、既存のオブジェクトのプロトタイプを変更することには使用されません。

function myFactory(){};
myFactory.prototype = someOtherObject;

var newChild = new myFactory;
newChild.__proto__ === myFactory.prototype === someOtherObject; //true

オブジェクトは内部に[[prototype]]プロパティを持っており、これは現在のプロトタイプを指しています。オブジェクトのプロパティが呼び出されるたびに、オブジェクトから始まり、ルートオブジェクトのプロトタイプの後に一致するか失敗するまで [[prototype]] チェーンを上がっていく仕組みになっています。これは、Javascript がオブジェクトの実行時の構築と修正を可能にする方法です。

__proto__ プロパティはいくつかの実装に存在します(現在は多く存在します): すべての Mozilla の実装、私が知っているすべての webkit の実装、その他です。このプロパティは内部の [[prototype]] プロパティを指し、オブジェクトの作成後の変更を可能にします。すべてのプロパティと関数は、この連鎖したルックアップにより、プロトタイプに一致するように即座に切り替わります。

この機能は、現在標準化されているとはいえ、まだ JavaScript の必須部分ではありませんし、それをサポートする言語では、あなたのコードを "unoptimized" のカテゴリに叩き落とす可能性が高くなります。JSエンジンはコードの分類に最善を尽くさなければならず、特に頻繁にアクセスされる "hot" コードは、もしあなたが __proto__ を修正するような派手なことをしている場合、あなたのコードをまったく最適化しません。

この投稿は https://bugzilla.mozilla.org/show_bug.cgi?id=607863 の現在の実装を特に議論しています。 __proto__ の現在の実装と、それらの間の違いについて具体的に説明しています。なぜなら、これは難しく未解決の問題だからです。Javascriptでは、a.) 構文 b.) ホストオブジェクト (DOMは技術的にはJavascriptの外に存在します) と c.) を除いて、すべてが変更可能です。 __proto__ . 残りは完全にあなたや他のすべての開発者の手に委ねられているので、なぜ __proto__ が突出している理由がわかると思います。

ひとつだけ __proto__ それは、オブジェクトのプロトタイプをそのコンストラクタとは別に実行時に指定することです。これは重要なユースケースであり、また __proto__ がまだ死んでいない主な理由の 1 つです。これは、Harmony、またはまもなく ECMAScript 6 として知られるようになるものの策定において、重大な論点となったほど重要なことなのです。オブジェクトの作成時にプロトタイプを指定する機能は、Javascript の次のバージョンの一部となり、これがベルを示すことになります。 __proto__ の日数が正式に決定されました。

短期的には __proto__ をサポートしているブラウザをターゲットにしている場合は、それを使用できます (IE ではありませんし、今後もそうなることはないでしょう)。ES6 が完成するのは 2013 年なので、今後 10 年間は webkit と moz で動作する可能性があります。

Brendan Eich - re: ES5 の新しい Object メソッドのアプローチ :

<ブロッククオート

申し訳ありませんが、......設定可能な __proto__ は、オブジェクトのイニシャライザーのユースケース(つまり、ES5 の Object.create に類似した、まだ到達していない新しいオブジェクト)を除けば、ひどいアイデアです。私はこれを、設定可能な __proto__ を 12 年以上前に設計し、実装したことがあります。

... 階層化されていないことが問題(JSONデータでキーが "__proto__" ). さらに悪いことに、ミュータビリティは、ilooping を避けるために、実装がプロトタイプの循環的な連鎖をチェックする必要があることを意味します。 [無限再帰のための一定のチェックが必要] です。

最後に、ミューティング __proto__ を実行すると、新しいプロトタイプオブジェクトの非ジェネリックメソッドが壊れる可能性があり、そのメソッドは __proto__ が設定されているレシーバ (直接の) オブジェクトでは動作しない可能性があります。これは単に悪い習慣であり、一般に意図的な型の混乱の一形態です。