Зачем использовать typeof для идентификации функции?

Есть ли существенные причины для использования

typeof variable === 'function'

против

!!variable.call

для определения, является ли переменная функцией?

Кроме очевидного, кто-то может создать такой объект, как:

{ call: 1 }

Проблема, которая у меня есть, заключается в том, что

typeof /regex/ === 'function'

возвращает true, но

!!/regex/.call

возвращает false

Ответ 1

Самый безопасный способ - проверить внутреннее свойство [[Class]], установив объект как аргумент thisArg метода .call() при вызове Object.prototype.toString.

Object.prototype.toString.call( myVariable ) === '[object Function]';

Конечно, вы можете легко сделать из него функцию:

function checkClass( obj ) {
    return Object.prototype.toString.call( obj ).slice( 8, -1).toLowerCase();
}

checkClass( myVariable ) === 'function';

Это очень просто, и могут быть некоторые улучшения, но вы получите эту идею.

Ответ 2

В соответствии со спецификацией ECMAScript для литералов регулярных выражений следует применять следующее:

Литерал регулярного выражения - это элемент ввода, который преобразуется в объект RegExp (раздел 15.10) при его проверке. Объект создается до того, как начнется оценка содержащейся программы или функции.

So typeof /regex/ должен давать "object":

typeof /regex/ === "object"

И конструктор объекта, созданного литералом регулярных выражений, должен быть RegExp:

/regex/.constructor === RegExp

Подобно этому, определение функции должно давать объект Function:

(function(){}).constructor === Function

Но хотя это возвращает объект Function, оператор typeof не должен давать "object", а "function" вместо:

typeof function(){} === "function"

Это связано с различием того, реализует ли объект внутреннее свойство [[Call]], которое является особенным для Объекты функции.

Обратите внимание, что все это должно вести себя как реализация Javascript. Итак, все уравнения утверждены как истинные.

Ответ 3

Проверьте предположения в сообщении (см. комментарий Gumbo).

typeof /regex/ === 'function'

Это возвращает false в Firefox 3.6.13.

Просто для развлечения, Firefox 3.6.13:

typeof /regex/                    // "object"
/regex/ instanceof RegExp         // true
/regex/.constructor.name          // RegExp
(function () {}).constructor.name // Function

IE8:

typeof /regex/                    // "object"
/regex/ instanceof RegExp         // true
/regex/.constructor.name          // undefined
(function () {}).constructor.name // undefined

Chrome 9:

typeof /regex/                    // "function"
/regex/ instanceof RegExp         // true
/regex/.constructor.name          // "RegExp"
(function () {}).constructor.name // "Function"

Ответ 4

Регулярное выражение является функцией

/bar/("bar") === ["bar"]

So typeof /bar/ === "function"

Хотя только хром распознает, что в качестве функции может использоваться литерал регулярного выражения. Должно ли это быть так или нет, для захвата. Вы можете рассматривать его так же, как функцию!

Ответ 5

jQuery isFunction устраняет проблему RegExp, которую вы указываете toString, - объект и проверяете результат на карте известных типов. Из последнего источника, здесь карта:

// Populate the class2type map
jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
    class2type[ "[object " + name + "]" ] = name.toLowerCase();
});

И вот как он используется:

type: function( obj ) {
    return obj == null ?
        String( obj ) :
        class2type[ toString.call(obj) ] || "object";
},

// See test/unit/core.js for details concerning isFunction.
// Since version 1.3, DOM methods and functions like alert
// aren't supported. They return false on IE (#2968).
isFunction: function( obj ) {
    return jQuery.type(obj) === "function";
},

Вы можете много узнать, прочитав источник jQuery.

Ответ 6

typeof variable === 'function' лучше, чем !!variable.call, потому что если переменная undefined или null, !!variable.call выдаст ошибку.