グローバルのtoString

JavaScriptでString型か判定する方法って色々あるけどどうするのがベストなんだっけなー、Underscore.jsでも参考にするかー、と思って調べてみたところ、こんな実装がされていました。

// eachは_.eachと同じ
each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
  _['is' + name] = function(obj) {
    return toString.call(obj) == '[object ' + name + ']';
  };
});

toStringで文字列比較する方法か、なるほどね。

と納得しそうだったのですが、よく見たらtoString.call(obj)って、え?グローバルなtoString?と一瞬ビビってしまいました。

良く良く考えてみるとwindowオブジェクトのプロパティには直接アクセスできるので、Window.prototype.toStringが参照されているだけでした。実際にはWindowクラスではtoStringが拡張されないので、Object.prototype.toStringが呼ばれるため、toString.call(obj)で"[object ...]"フォーマットの文字列を取得することが出来る仕組みです。ただ、ちゃんとObject.prototype.toString.call(obj)にした方が無難な気はしますが…。

そんなグローバルなtoStringですが、色々面白い話があるようで、GCとかのデバッグコンソールでは、toString !== window.toStringtoString === console.toStringだそうです。原則、デバッグコンソール内でもwindowオブジェクトには裸でアクセスできるのですが、一部はこの様に書き換わっていることがあるようです。

UnderscoreにおけるtoStringの参照

上記で、window.toStringを参照ししていると書きましたが、冒頭でtoStringにObject.prototype.toStringがセットされていました。一安心です。

  var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
  var
    push             = ArrayProto.push,
    slice            = ArrayProto.slice,
    concat           = ArrayProto.concat,
    toString         = ObjProto.toString,
    hasOwnProperty   = ObjProto.hasOwnProperty;