【JavaScript】プロトタイプチェーンは無限ループするのか
更新日:2023/04/17
JavaScriptでプロトタイプチェーンを追っていく関数を作成することになりました。
そこで問題になるのが、プロトタイプチェーンが親オブジェクトを参照することで発生する無限ループです。
その対策をしっかりとおこなう必要がありますが、そもそも無限ループするような状況を作成できるのでしょうか。
気になったので実験してみました。
結論:できなかった
まずはオブジェクトのプロトタイプチェーンをオブジェクト自身に変更してみる。
const aa = {a:1};
Object.setPrototypeOf(aa,aa);
console.log( aa.b );
これで aa[[protprype]]の参照先が aaになるので、aa.bを参照すると無限ループするはず。
実行してみた。
Object.setPrototypeOf(aa,aa)で、怒られた。
TypeError: can't set prototype: it would cause a prototype chain cycle
翻訳:プロトタイプ チェーン サイクルが発生します。
Firefoxでのメッセージです。
無限ループしないようにチェックしているのか…
この時点で、いろいろ対策しているのがうかがえる。
でも、もう少し実験してみる。
継承元のクラスのprototypeプロパティを変更して無限ループさせてみる。
const classA = class {
a=1;
};
const classB = class extends classA{
b=1
};
classB.prototype = classA;
const ca = new classB;
console.log( ca.c );
こうすると、ca[[prototype]] → classB[[prototype]] → ca になって無限ループするはず。
実行してみた。
無限ループしないで、undefinedになった。
console.log( ca.c ); // 結果: undefined
プロパティの属性を確認すると、上書き不可だった。
Object.getOwnPropertyDescriptor( classB , "prototype")
// Object { value: {…}, writable: false, enumerable: false, configurable: false }
対策されているようだ。
無限ループできるようだ
ネットで調べてみると、Proxyで無限ループさせている記事があった。
こんなコードです。
const target = {}
Object.setPrototypeOf(target, new Proxy(target, {}));
console.log( target.p );
new Proxy(target, {})の[[protprype]]はObject.prototypeを参照している。
だから、プロトタイプチェーンサイクルエラーにはならない。
しかしProxyの仕様上、プロパティ検索時のチェーン先はtargetのプロトタイプチェーンが使用される(たぶん)
これなら無限ループになりそうだ。
実行してみる。
エラーが出た。
InternalError: too much recursion
翻訳: 再帰が多すぎる
プロパティの検索は再帰でやってるから、スタックの上限でストップしました。
元から無限ループしない仕様になっていましたね。
それはともかく、ほぼ無限ループな状況をつくれました。
故意以外でこんな状況になるケースはなさそうですが、対策はしておくべきですね。
更新日:2023/04/17
関連記事
スポンサーリンク
記事の内容について
こんにちはけーちゃんです。
説明するのって難しいですね。
「なんか言ってることおかしくない?」
たぶん、こんなご意見あると思います。
裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。
そんなときは、ご意見もらえたら嬉しいです。
掲載コードについては事前に動作確認をしていますが、貼り付け後に体裁を整えるなどをした結果動作しないものになっていることがあります。
生暖かい視線でスルーするか、ご指摘ください。
ご意見、ご指摘はこちら。
https://note.affi-sapo-sv.com/info.php
このサイトは、リンクフリーです。大歓迎です。