7
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

配列をfreezeしてpopしても例外をはかないChromeさんとは

Last updated at Posted at 2013-08-23

夏も終わりに近づいてきて、少しずつ蚊などの虫も減ってきていますが、まだまだ世の中に生まれるバグは減りそうにありません。あらっきぃです。

何があったの?

ChromeやNode.jsに用いられているV8の現在の実装は、Object.freezeを適用した状態の配列に対して、Arrayの破壊的なメソッド(pop, push, splice等)を呼び出してもTypeError例外が発生しません。FirefoxとかIE10だと例外なんだけど…。

どういうことなのかというと、

'use strict'; //あってもなくても特に関係ない
var
arr = Object.freeze([1, 2, 3]);

console.log(arr.pop()); //=> Chromeだと3が返る。FirefoxだとTypeError
arr.push(4); //=> FirefoxだとTypeError
console.log(arr); //=> [1, 2, 3] (配列自身は変更されない)

と、コメントに書いたような事態になります。

これって仕様的(ES5)にまずいんじゃない? って気がしたのでStack Overflowで訊いてみたら、案の定仕様に反しているとのことでした。

ぶっちゃけ、V8の/src/array.jspopなどの定義に、

array.js
//417行目あたり
function ArrayPop() {
  'use strict';
  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
    throw MakeTypeError("called_on_null_or_undefined",
                        ["Array.prototype.pop"]);
  }
  ...

'use strict'を書くだけでpopとかで例外を吐くようになるんですけど、そう簡単にはいかないめんどくさい事情があるみたいです、V8の開発陣には。
大人しく仕様準拠すればいいものを…。

何が問題なの?

これで何が問題なのかというと――って言うまでもないかと思いますが、Object.freezeを使うときはそのオブジェクトに対して破壊的な操作をされたくないときになります。なので当然、poppushされたくないわけです。でもって、それが禁止されているなら、できることなら実行したときに教えてくれるとありがたいです。というか、意図してObject.freezeを使うぐらいですからそれを期待します。
ここからは例え話ですが、上のような意図をもってObject.freezeを使ったライブラリを作ったとします。そのことをライブラリの作成者はうっかりリファレンスに記述し忘れて、利用者はそのことを知りません。となると、利用者はそれが普通に配列であると信じてpoppushを行うかもしれませんが、Chromeさんは困ったことにその配列を変更しようとしても例外を吐かず、しかも配列が変更されていないというかなり不可解な事態に陥ってしまいます。これって知らないとすぐには気付けないバグになりますよね。

締め

こういうことって知らないと割と悩む原因になるので、僕みたいに時間を無駄にする人が後生に現れ無いようにと書いてみました。あとStack Overflowで訊いたら「英語を読みやすく直してやったよ」と言って質問の内容を書き改められたのが衝撃的でした。

それではっ。


参考

7
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?