Почему UnderscoreJS использует toString.call() вместо typeof?

Глядя под капот в UnderscoreJS, я вижу:

  _.isFunction = function(obj) {
    return toString.call(obj) == '[object Function]';
  };

  _.isString = function(obj) {
    return toString.call(obj) == '[object String]';
  };

  _.isNumber = function(obj) {
    return toString.call(obj) == '[object Number]';
  };

Это кажется странным выбором. Почему бы просто не использовать typeof, чтобы определить, является ли значение строкой, функцией или номером? Есть ли увеличение производительности при использовании toString? Не поддерживается ли типof более старыми браузерами?

Ответ 1

Ну, на самом деле это потому, что быстрее проверить [[Class]], проверив с помощью toString. Также может быть меньше ошибок, поскольку toString дает вам точный класс...

проверьте это:

var fn = function() { 
    console.log(typeof(arguments)) // returns object
    console.log(arguments.toString()) // returns object Arguments
}

Здесь вы можете увидеть эталон для символа подчеркивания типа vs toString:

http://jsperf.com/underscore-js-istype-alternatives

Также есть некоторые проблемы github с лучшим объяснением:

https://github.com/documentcloud/underscore/pull/332

https://github.com/documentcloud/underscore/pull/321

ИЗМЕНИТЬ 1:

Вы также можете проверить эту замечательную статью:

http://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/

Ответ 2

ответ drinnhev частично корректен. toString в настоящее время намного медленнее, чем использование typeOf в большинстве браузеров. См. 7-ю ревизию теста, который он опубликовал, который использует typeOf. Оба они все еще очень быстры, хотя в большинстве случаев эта разница в производительности не будет заметной, а компромисс стоит соответствовать спецификациям лучше, чем утка typing/typeOf.

Запрос на выделение подчеркивания 321 (который указан в списке), содержит подробное обсуждение компромиссов и почему они решили использовать toString.