Как я могу проверить, является ли переменная javascript типом функции?
предположим, что у меня есть какая-либо переменная, которая определяется следующим образом:
var a = function() {/* Statements */};
мне нужна функция, которая проверяет, является ли тип переменной функциональным. т. е. :
function foo(v) {if (v is function type?) {/* do something */}};
foo(a);
Как я могу проверить, является ли переменная ' a ' функцией типа так, как определено выше?
17 ответов:
конечно, способ подчеркивания более эффективен, но лучший способ проверить, когда эффективность не является проблемой, написан на странице подчеркивания, связанной с @Paul Rosania.
вдохновленный подчеркиванием, конечная функция isFunction выглядит следующим образом:
function isFunction(functionToCheck) { return functionToCheck && {}.toString.call(functionToCheck) === '[object Function]'; }
подчеркивания.js использует более сложный, но высокоэффективный тест:
_.isFunction = function(obj) { return !!(obj && obj.constructor && obj.call && obj.apply); };см.:http://jsperf.com/alternative-isfunction-implementations
EDIT: обновленные тесты показывают, что typeof может быть быстрее, см. http://jsperf.com/alternative-isfunction-implementations/4
есть несколько способов, так что я буду суммировать их все
- лучший способ:
function foo(v) {if (v instanceof Function) {/* do something */} };Наиболее производительное (без сравнения строк) и элегантное решение - оператор instanceof поддерживается в браузерах уже очень давно, так что не волнуйтесь - он будет работать в IE 6.- следующий лучший способ:
function foo(v) {if (typeof v === "function") {/* do something */} };недостатокtypeofэто то, что он подвержен молчаливому отказу, плохо, поэтому, если у вас есть опечатка (например, "finction") - в этом случае " если` просто вернет false и ты не знаешь, что у тебя ошибка в коде- следующий лучший способ:
function isFunction(functionToCheck) { var getType = {}; return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]'; }Это не имеет никакого преимущества перед решением №1 или № 2, но намного менее читаемо. Улучшенная версия этого являетсяfunction isFunction(x) { return Object.prototype.toString.call(x) == '[object Function]'; }но все же намного меньше семантики, чем Решение №1
@grandecomplex: в вашем решении довольно много многословия. Было бы гораздо яснее, если бы написано так:
function isFunction(x) { return Object.prototype.toString.call(x) == '[object Function]'; }
попробуйте instanceof: кажется, что все функции наследуются от класса "Function":
// Test data var f1 = function () { alert("test"); } var o1 = { Name: "Object_1" }; F_est = function () { }; var o2 = new F_est(); // Results alert(f1 instanceof Function); // true alert(o1 instanceof Function); // false alert(o2 instanceof Function); // false
другой простой способ:
var fn = function () {} if (fn.constructor === Function) { // true } else { // false }
для тех, кто интересуется функциональным стилем или ищет более выразительный подход к использованию в метапрограммировании (например, проверка типа), было бы интересно посмотреть Ramda библиотека для выполнения таких задач.
следующий код содержит только чистые и pointfree функции:
const R = require('ramda'); const isPrototypeEquals = R.pipe(Object.getPrototypeOf, R.equals); const equalsSyncFunction = isPrototypeEquals(() => {}); const isSyncFunction = R.pipe(Object.getPrototypeOf, equalsSyncFunction);по состоянию на ES2017,
asyncфункции доступны, поэтому мы можем проверить их также:const equalsAsyncFunction = isPrototypeEquals(async () => {}); const isAsyncFunction = R.pipe(Object.getPrototypeOf, equalsAsyncFunction);а затем объединить их вместе:
const isFunction = R.either(isSyncFunction, isAsyncFunction);конечно, функция должна быть защищена от
nullиundefinedзначения, так, чтобы сделать его "безопасным":const safeIsFunction = R.unless(R.isNil, isFunction);и, полный фрагмент, чтобы подвести итог:
const R = require('ramda'); const isPrototypeEquals = R.pipe(Object.getPrototypeOf, R.equals); const equalsSyncFunction = isPrototypeEquals(() => {}); const equalsAsyncFunction = isPrototypeEquals(async () => {}); const isSyncFunction = R.pipe(Object.getPrototypeOf, equalsSyncFunction); const isAsyncFunction = R.pipe(Object.getPrototypeOf, equalsAsyncFunction); const isFunction = R.either(isSyncFunction, isAsyncFunction); const safeIsFunction = R.unless(R.isNil, isFunction); // --- console.log(safeIsFunction( function () {} )); console.log(safeIsFunction( () => {} )); console.log(safeIsFunction( (async () => {}) )); console.log(safeIsFunction( new class {} )); console.log(safeIsFunction( {} )); console.log(safeIsFunction( [] )); console.log(safeIsFunction( 'a' )); console.log(safeIsFunction( 1 )); console.log(safeIsFunction( null )); console.log(safeIsFunction( undefined ));однако, обратите внимание, что это решение может показать меньшую производительность, чем другие доступные варианты из-за широкого использования функций более высокого порядка.
Если вы используете Lodash вы можете сделать это с _.isFunction.
_.isFunction(function(){}); // => true _.isFunction(/abc/); // => false _.isFunction(true); // => false _.isFunction(null); // => falseэтот метод возвращает
trueесли значение является функцией, то elsefalse.
я обнаружил, что при тестировании собственных функций браузера в IE8, используя
toString,instanceofиtypeofне работает. Вот метод, который отлично работает в IE8 (насколько я знаю):function isFn(f){ return !!(f && f.call && f.apply); } //Returns true in IE7/8 isFn(document.getElementById);кроме того, вы можете проверить, для собственных функций с помощью:
"getElementById" in documentхотя, я где-то читал, что это не всегда будет работать в IE7 и ниже.
Я думаю, что вы можете просто определить флаг на прототипе функции и проверить, если экземпляр, который вы хотите проверить, унаследовал это
определить флаг:
Function.prototype.isFunction = true;и затем проверить, если он существует
var foo = function(){}; foo.isFunction; // will return trueнедостатком является то, что другой прототип может определить тот же флаг, а затем он бесполезен, но если у вас есть полный контроль над включенными модулями, это самый простой способ
начиная с узла v0. 11 вы можете использовать стандартную функцию util:
var util = require('util'); util.isFunction('foo');
ниже, кажется, работает и для меня (проверено с
node.js):var isFunction = function(o) { return Function.prototype.isPrototypeOf(o); }; console.log(isFunction(function(){})); // true console.log(isFunction({})); // false
вы должны использовать
typeOfоператор в js.var a=function(){ alert("fun a"); } alert(typeof a);// alerts "function"
решение, как показали некоторые предыдущие ответы, заключается в использовании typeof. ниже приведен фрагмент кода в NodeJs,
function startx() { console.log("startx function called."); } var fct= {}; fct["/startx"] = startx; if (typeof fct[/startx] === 'function') { //check if function then execute it fct[/startx](); }
Comments