JavaScriptの this での文字列と数値の扱い

#<i class="fa fa-book"></i> はじめに

JavaScriptの `this` は割と厄介だけど便利でもある存在ですが、この `this` に文字列や数値が入る場合、知らないと「あれ？」ってなる現象が起こります。

#<i class="fa fa-frown-o"></i> 数値や文字列が `'object'` 判定になる！？

jQueryの `$.each()` で配列やオブジェクトをループさせることはよくある事かと思います。
このメソッドでは `this` は配列やオブジェクトの値が入っているわけですが……

```js:とある配列の値の型を調べる
var arr = [123, NaN, Infinity, 'abc'];

$.each(arr, function (i) {
  var type = typeof this;
  console.log(i + ': ' + this + ' is ' + type);
});
// 0: 123 is object
// 1: NaN is object
// 2: Infinity is object
// 3: abc is object
```

あれ？ `typeof` で調べたら全部 `'object'` になってしまいました。

他にも、例えば `Function.prototype.call()` や `Function.prototype.bind()` で `this` に値を入れても同じ結果になります。

```js:thisに入ってる値の型を調べる
function typeOfThis() {
  return typeof this;
}

typeOfThis.call(123);       // 'object'
typeOfThis.call(NaN);       // 'object'
typeOfThis.call(Infinity);  // 'object'
typeOfThis.call('abc');     // 'object'

typeOfThis.bind(123)();     // 'object'
```

##`this` の値を見てみる

普通に計算にしたり文字列結合できたりするのに、なぜ `typeof` で調べると `'object'` なのか。
`console.dir()` で `this` がどうなっているか見てみます。

```js:Chromeで実行した例
function thisTest() {
  console.dir(this);
}

thisTest.call(123);
/*
Number
  __proto__: Number
    constructor: function Number()
    ～省略～
  [[PrimitiveValue]]: 123
*/

thisTest.call(NaN);
/*
Number
  __proto__: Number
    constructor: function Number()
    ～省略～
  [[PrimitiveValue]]: NaN
*/

thisTest.call(Infinity);
/*
Number
  __proto__: Number
    constructor: function Number()
    ～省略～
  [[PrimitiveValue]]: Infinity
*/

thisTest.call('abc');
/*
String
  0: "a"
  1: "b"
  2: "c"
  length: 3
  __proto__: String
    constructor: function String()
    ～省略～
  [[PrimitiveValue]]: "abc"
*/
```

よくわからない部分もあるかと思いますが、数値リテラルや文字列リテラルではなく数値オブジェクトや文字列オブジェクトとして `this` に入っているのがわかります。
要するに、`new Number(123)` や `new String('abc')` 等で生成したのと同じものになります。だから `typeof` では `'object'` になってしまうんですね。

`this` にはオブジェクトが入るべきという感じでしょうか。（実はよく知らないですごめんなさい）

#<i class="fa fa-smile-o"></i> こうすれば解決できる

じゃあどうすればいいか、こういった方法があります。

##jQueryであれば第2引数を使う

`$.each()` のコールバック関数の第2引数にも配列やオブジェクトの値を取ることができます。

```js:とある配列の値の型を調べる
var arr = [123, NaN, Infinity, 'abc'];

$.each(arr, function (i, value) {
  var type = typeof value;
  console.log(i + ': ' + value + ' is ' + type);
});
// 0: 123 is number
// 1: NaN is number
// 2: Infinity is number
// 3: abc is string
```

`this` で扱うよりも自然な感じがしてわかりやすいので、こちらの使い方の方が個人的にはいいのではと思います。

##Strictモードにしてしまう

`'use strict';` をコードの頭に置くことにより、ブラウザがそのコードをStrictモードとして扱います。
Strictモードは厳格な処理を行い、`this` にはそのままの型で入るようになります。

```js:とある配列の値の型を調べる
var arr = [123, NaN, Infinity, 'abc'];

$.each(arr, function (i) {
  'use strict';
  var type = typeof this;
  console.log(i + ': ' + this + ' is ' + type);
});
// 0: 123 is number
// 1: NaN is number
// 2: Infinity is number
// 3: abc is string
```

`Function.prototype.call()` でも同様に。

```js:thisに入ってる値の型を調べる
function typeOfThis() {
  'use strict';
  return typeof this;
}

typeOfThis.call(123);       // 'number'
typeOfThis.call(NaN);       // 'number'
typeOfThis.call(Infinity);  // 'number'
typeOfThis.call('abc');     // 'string'
```

ただ、Strictモードに対応しているブラウザでないと意味がありません。
素直に引数として渡した方が確実な気もします……

##普通に引数として渡す

ぶっちゃけ、`this` に入れる必要がないのであれば、引数として扱うべきです。

```js:thisに入ってる値の型を調べる
function typeOf(obj) {
  return typeof obj;
}

typeOf(123);       // 'number'
typeOf(NaN);       // 'number'
typeOf(Infinity);  // 'number'
typeOf('abc');     // 'string'
```

#<i class="fa fa-coffee"></i> おわりに

会社の同僚がこれの沼にどはまりしていたので、やはり知らない人もいるのだと思いメモとして書きました。
jQueryに限った事ではないですが、`this` を取り扱う場合はしっかりと把握しておく必要がありますね。