Safari でのクラッシュを修正2006年11月21日 20時13分

Safari でこのブログを見るとクラッシュすることがあった問題ですが、私の書いたスクリプトに原因がありました。

var Klass = function () {
  if (this.constructor != arguments.callee)
    return new arguments.callee();

  /* Initialize object... */
};

これは「クラスの機能と関数の機能を併用」を基にしたもので、Klass() のように関数として呼び出されたときも、new Klass() と呼び出されたときと同じく Klass オブジェクトを返すための処理なのですが、これが期待通り働くためには Klass.prototype.constructor == Klass が成り立っていないといけません。しかし、Safari には関数式により作られた関数オブジェクト f に関して、f.prototype.constructor が設定されない (f.prototype.hasOwnProperty("constructor") == false となる) というバグがあるため、条件式が常に真と判断され、結果無限再帰に陥りクラッシュしてしまうようです。

修正案として真っ先に考えられるのは Klass.prototype.constructor = Klass と明示的に constructor プロパティを設定することですが、これを書いている途中でそれよりも条件式を !(this instanceof arguments.callee) にしたほうがいいと思い当たりました。でないと以下のような場合に不具合がおきます。

function Super(x) {
  if (!(this instanceof arguments.callee))
    return new arguments.callee(x);
  this.x = x;
  return this; // SpiderMonkey での警告を避ける
}

function Sub(x) {
  Super.apply(this, arguments);
}
Sub.prototype = new Super();
Sub.prototype.constructor = Sub;

print(new Sub(42).x); // 42
// if (this.constructor != arguments.callee) だと
// new Sub(42).x === undefined となる

しかし Safari がクラッシュするというのならアクセス解析に残っていた Safari の記録は何なのだろうと思って見直したら、どうもアクセス解析にあるのは Safari 2 (WebKit のビルド番号 400 番代) だけみたいです。原因となったバグ自体は Safari 2 でも直っていないのでエラーは出ているはずですが、クラッシュはしないように修正されたのでしょうか。

それにしても Safari を使っている人には 2 か月近くこのブログはブラクラと化していたわけで申し訳ないことです。おまけにこのバグは Safari の JavaScript の不備にも載せてあったもので、自分で引っかかるとはまったく情けない限りです。

コメント

コメントをどうぞ

※メールアドレスとURLの入力は必須ではありません。 入力されたメールアドレスは記事に反映されず、ブログの管理者のみが参照できます。

※投稿には管理者が設定した質問に答える必要があります。

名前:
メールアドレス:
URL:
次の質問に答えてください:
「ハイパーテキストマークアップ言語」をアルファベット4文字でいうと?

コメント:

トラックバック

このエントリのトラックバックURL: http://nanto.asablo.jp/blog/2006/11/21/963493/tb