IE8でうまく動かないJavaScript

これまで色々と罠にハメられたことのメモ。
Windows版のIE9以降では動くけどIE8では動かないコード。

これまで遭遇した中でも、あんまり再現条件が限定的だったりするものや経緯が複雑だったものは省いています。

<p>
<ins>
(2015/08/26 追記)
いくつかの現象は IE8 が ECMAScript3 をベースに、IE9 以上が ECMAScript5 をベースに動作することが原因で発生する現象です。
それらについても追記しました。
</ins></p>

# グローバル変数を <code>delete</code> 演算子で削除しようとするとエラー

何でなのかわかりません。調べる気も起きませんでした……

```js
window.hoge = 'abc';

// エラー
delete window.hoge; // このオブジェクトではサポートされていない操作です
// 代わりに↓で代用する
window.hoge = void 0; // void 0 は undefined のこと
```

ECMAScript3 の <a href="http://www2u.biglobe.ne.jp/~oz-07ams/2002/ecma262r3/11_Expressions.html#section-11.4.1" target="_blank"><code>delete</code> 演算子</a>および <a href="http://www2u.biglobe.ne.jp/~oz-07ams/2002/ecma262r3/15-1_Global_Object.html" target="_blank"><code>Global</code> オブジェクト</a>についてこのような仕様の言及は無さそうです。
IE8 の Global オブジェクト（＝window）には <code>[[Delete]]</code> メソッドが定義されていないということでしょうか。

# DOMエレメントの存在しないプロパティを <code>delete</code> 演算子で削除しようとするとエラー

削除できるうちは大丈夫らしい。

```js
var elem = document.getElementById('fooBar');

elem.foo = 'bar';

delete elem.foo; // true
delete elem.foo; // オブジェクトでサポートされていないプロパティまたはメソッドです。
```

`delete` 演算子の仕様的に説明がつかないような……

# <code>String</code> オブジェクトに添え字アクセスすると <code>undefined</code>

やる方が悪い。が、IE9以降では動いてしまうのだ。
特に `String.prototype` にメソッドを拡張するときに `this` が `String` オブジェクトになってしまうので注意。
そもそも `charAt` メソッドを使用しましょう。

> 文字への配列のようなアクセス方法（上記のふたつめの方法）は、 ECMAScript 3 仕様には含まれていません。これらは JavaScript と ECMAScript 5 の機能です。
> https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String

```js
var str = 'abc';
var strObj = new String(str);

// Stringオブジェクト＋添え字を組み合わせると文字が取得できない
console.log(strObj[1]); // undefined
// charAt を使えば大丈夫
console.log(strObj.charAt(1)); // 'b'
// string型のプリミティブなら大丈夫
console.log(str[1]); // 'b'

// string型で扱いつつcharAtを使うのが最も無難
console.log(str.charAt(1)); // 'b'

// こんな風にメソッドを追加する場合、this が String オブジェクトにラップされているので注意が必要
String.prototype.lastChar = function() {
    return this[this.length - 1]; // IE8 だけ常に undefined が返る
};
```

添え字によるアクセスが出来ないこと自体は ECMAScript3 の仕様なので全部が全部 IE8 が悪いわけではないですが、以下の点で嫌らしいです。

* `string` 型の値（`String` オブジェクトでないプリミティブ値）では添え字アクセスが可能
* IE9以降だと動いてしまう（ECMAScript5 で仕様が見直された影響）

誰が悪いとかいう話ではないですが、気をつけた方がいいかと思います（特にインデックスアクセス可能な別言語に慣れている方はやらかしやすい模様です）。

# <code>parseInt</code> に <code>'08'</code>, <code>'09'</code> を渡すと <code>0</code> にされる

8進数で解釈されるためです。`'08'`, `'09'` は8進数として不正なため `0` にされます。
そもそも `parseInt` を使う意図がなければ私は `Number` 関数派です。

```js
console.log(parseInt('07')); // 7
console.log(parseInt('08')); // 0

console.log(Number('07')); // 7
console.log(Number('08')); // 8
```

参考: [茨城県と栃木県のデータがおかしいときに確かめること](http://qiita.com/isseium/items/6c7841122fb380a51fe6)

これは ECMAScript3 の仕様…と言いたいところですが、[15.1.2.2 parseInt (string , radix)](http://www2u.biglobe.ne.jp/~oz-07ams/2002/ecma262r3/15-1_Global_Object.html#section-15.1.2.2) には以下の記載があるので残念だとは思います。

> `radix` が `0` または `undefined` であり、 `string` の数が数字 `0` で始まり `x` も `X` も続かないとき、実装は、自由な判断で、数を 8 進数とも 10 進数とも解釈してよい。実装はこの場合、 10 進数として数を解釈することが推奨される。

# innerHTML に改行コードを含む文字列を代入したあと取り出すと改行コードが消える

以下のコードは IE8 と IE9 以降で動きが違う。

```js
var foo = document.getElementById('foo');
foo.innerHTML = 'hoge \r\n fuga';
console.log( foo.innerHTML ); // IE8では改行コードが消える
```

それに伴い、例えば jQuery で以下のコードの結果も変わる。

```js
var text = 'hoge \r\n fuga';
console.log( $('#foo').text(text).html() ); // IE8 では \r\n が消える
```

…こんな仕様の違いに左右されるコードを書かないでよって気もしますが、某ライブラリがこういうことをしていて現象に遭遇したのと、過去にも同じ話に遭遇した記憶があるなぁと思ったのでメモ。