Зачем использовать 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
выдаст ошибку.