変数が関数型かどうかを確認します


904

次のように定義されている変数があるとします。

var a = function() {/* Statements */};

変数の型が関数に似ているかどうかをチェックする関数が必要です。すなわち:

function foo(v) {if (v is function type?) {/* do something */}};
foo(a);

変数aFunction上記で定義された方法で型かどうかを確認するにはどうすればよいですか?


2
ここで、このjsben.ch/#/e5Ogr
EscapeNetscape

回答:


380

確かにアンダースコアの方が効率的ですが、効率が問題でない場合にチェックする最良の方法は、@ Paul Rosaniaによってリンクされたアンダースコアのページに書かれています。

下線に触発された最終的なisFunction関数は次のとおりです。

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

1
この問題についてより広範囲な調査を行ったが、単純な「結果検証」を使用してjsperfのリビジョン4の結果を確認する人がいるかもしれません。isFunctionAは、他の方法と比較した実装の違いを示しています。
Joel Purra、

24
、更新パフォーマンステストお使いのブラウザによっては巨大な速度差がありますように見えます。Chromeではtypeof(obj) === 'function'、最速のようです。ただし、Firefoxではobj instanceof Function明らかに勝者です。
ジャスティンウォーケンティン2012年

7
パーツに関して:typeofは、変数またはプロパティが未定義かどうかを確認するためにのみ使用する必要があります。typeofの適切な使用」セクションのjavascript.info/tutorial/type-detectionで、次のように著者は述べています。ケースはまったく逆です
Konrad Madej

11
アレックス、なぜtypeofが未定義かどうかをチェックするためだけに使用されるべきだと言うのが気になります。その名前は、その目的が存在するかどうかだけでなく、何かのタイプをチェックすることであることを示唆しています。それを使用して型チェックを行うときに発生する可能性のある技術的な問題や問題はありますか、それともより優先されますか?警告がある場合は、他の人がつまずくのを避けることができるようにそれらをリストすることをお勧めします。
jinglesthula 2014年

14
過度に複雑なソリューション
Daniel Garmoshka

1713
if (typeof v === "function") {
    // do something
}

44
ただ、のようないくつかのことに気をつけtypeof Objecttypeof Dateおよびtypeof String、そのすべての戻り'function'すぎ。
Dave Ward、

358
@デイブ、それらは関数なので問題は何なのかわかりません。
Matthew Crumley、

6
とはどう違いif (v instanceOf Function)ますか?
mquandalle 2013

10
@mquandalle大きな違いはありませんinstanceofが、別のドキュメント(iframeなど)の関数をチェックしている場合は機能しません。パフォーマンスはさまざまです。
rvighne 2014

8
受け入れられた回答とは異なり、これは非同期関数でも機能します。の場合asyncfunctionToCheckgetType.toString.call(functionToCheck)==='[object AsyncFunction]'ここでtypeof asyncfunctionToCheck === 'function'
TDreama 2017年

132

Underscore.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を


このアプローチを使用する特別な理由はありますtypofか?
sv_in '14年

1
Underscoreのバージョンは、ほとんどのブラウザーではるかに高速です。参照:jsperf.com/alternative-isfunction-implementations
ポールロザニア

13
アンダースコア、シンプルだけどパワフルなものが好きです。とは言え、この実装がそれらの属性を持つオブジェクトによって偽装される可能性があることはおそらく注目に値します。
studgeek 2011

3
@PaulRosaniaこれらのパフォーマンステストを本日初めに偶然見つけ、リビジョン4として検証とより多くのテストデータで更新しました -ブラウザテストカバレッジを増やすために実行してください。(多くのテストのため)1秒あたりの操作は遅いですが、1つの実装の違いも示しています(JavaScriptコンソールを開いてページを再読み込みしてください。ログに記録されたエラーメッセージがある場合があります)。注:リビジョン3にisFunctionDが追加されました(のみに基づいていますtypeof == "function")。Underscore の「高速」バージョンよりはるかに高速のようです。
Joel Purra

6
Underscore.jsが代替実装のテストの上記で参照されたリビジョン4ではなく、リビジョン12にあるため、この回答は少し誤解を招く可能性がありますisFunction()。それは現在、ダンデーンが示唆したものに非常に近いものを使用しています。
ジョナサンユーニス、2013年

112

いくつかの方法があるので、それらすべてを要約します

  1. 最善の方法は:
    function foo(v){if(v instanceof Function){/ *何かをする* /}};
    
    
    ほとんどのパフォーマンス(文字列比較なし)でエレガントなソリューション-instanceof演算子はブラウザーで非常に長い間サポートされているので、心配しないでください-IE 6で動作します。
  2. 次の最良の方法は:
    function foo(v){if(typeof v === "function"){/ *何かをする* /}};
    
    
    不利な点typeofは、サイレントエラーの影響を受けやすいことです。悪いため、タイプミスがある場合(たとえば、「finction」)-この場合、 `if`はfalseを返すだけで、後でエラーが発生することがわかりますあなたのコード
  3. 次善の方法は次のとおりです。
    function isFunction(functionToCheck){
        var getType = {};
        return functionToCheck && getType.toString.call(functionToCheck)=== '[オブジェクト関数]';
    }
    
    
    これは、ソリューション#1または#2に勝る利点はありませんが、読みにくくなります。これの改良版は
    function isFunction(x){
        return Object.prototype.toString.call(x)== '[オブジェクト関数]';
    }
    
    
    しかし、ソリューション#1よりもセマンティックがはるかに少ない

10
関数が別のフレームコンテキストに渡された場合、最初のソリューションは失敗します。たとえば、iframeからtop.Function !== Function。確かに、2番目のものを使用してください(「関数」のスペルミスはデバッグ中に修正されると幸いです)。
MaxArt 2014

タイプミスに関するあなたのポイントについて:このタイプミスがあるコードはすぐに失敗する可能性が高く、タイプミスに基づく他のどのバグよりも明白ではありません。typeof ===「関数」が最もクリーンなソリューションです。さらに、使用する「最良の」ソリューションはinstanceof、フレーム全体のチェックなどの複数のグローバルを考慮せず、偽陰性を返す可能性があります。
ブレインキム


56

@grandecomplex:ソリューションにはかなりの冗長性があります。次のように書くと、より明確になります。

function isFunction(x) {
  return Object.prototype.toString.call(x) == '[object Function]';
}

Object.prototype.toString.callは、関心のある他のjavascriptタイプに役立ちます。nullまたはundefinedに対してチェックすることもできるため、非常に強力です。
Jason Foglia

49

var foo = function(){};
if (typeof foo === "function") {
  alert("is function")
}


1
...そして(() => (typeof obj === 'function') && doSomething())最速のオプションです。
ダーチャー

35

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

19

より多くのブラウザーサポートがあり、非同期関数も含まれているものは次のとおりです。

const isFunction = value => value && (Object.prototype.toString.call(value) === "[object Function]" || "function" === typeof value || value instanceof Function);

そしてそれを次のようにテストします:

isFunction(isFunction); //true
isFunction(function(){}); //true
isFunction(()=> {}); //true
isFunction(()=> {return 1}); //true
isFunction(async function asyncFunction(){}); //true
isFunction(Array); //true
isFunction(Date); //true
isFunction(Object); //true
isFunction(Number); //true
isFunction(String); //true
isFunction(Symbol); //true
isFunction({}); //false
isFunction([]); //false
isFunction("function"); //false
isFunction(true); //false
isFunction(1); //false
isFunction("Alireza Dezfoolian"); //false


9

関数型に興味がある、またはメタプログラミング(型チェックなど)で利用するためのより表現力豊かなアプローチを探している人にとって、Ramdaを見るのは興味深いかもしれませんようなタスクを達成するためにライブラリを。

次のコードには、純粋でポイントフリーの関数のみが含まれています。

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);

もちろん、関数を「安全」にするには、関数nullundefined値から保護する必要があります。

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 ));

ただし、このソリューションでは、高次関数が頻繁に使用されるため、他の利用可能なオプションよりもパフォーマンスが低下する可能性があることに注意してください。


7

Lodashを使用する場合は、_。isFunctionを使用して実行できます。

_.isFunction(function(){});
// => true

_.isFunction(/abc/);
// => false

_.isFunction(true);
// => false

_.isFunction(null);
// => false

このメソッドはtrue、値が関数である場合は戻り、それ以外の場合は戻りますfalse


4

私はIE8でネイティブブラウザの機能をテストする場合、使用することがわかったtoStringinstanceoftypeof動作しませんでした。IE8で正常に機能する方法は次のとおりです(私の知る限り)。

function isFn(f){
    return !!(f && f.call && f.apply);
}
//Returns true in IE7/8
isFn(document.getElementById);

または、次のコマンドを使用してネイティブ関数を確認できます。

"getElementById" in document

しかし、IE7以下ではこれが常に機能するとは限らないことをどこかで読んだことがあります。


4

以下も私にとってはうまくいくようです(からテストされましたnode.js):

var isFunction = function(o) {
     return Function.prototype.isPrototypeOf(o);
};

console.log(isFunction(function(){})); // true
console.log(isFunction({})); // false

4

関数プロトタイプにフラグを定義して、テストするインスタンスがそれを継承しているかどうかを確認するだけでよいと思います

フラグを定義します。

Function.prototype.isFunction = true; 

それが存在するかどうかを確認します

var foo = function(){};
foo.isFunction; // will return true

欠点は、別のプロトタイプが同じフラグを定義でき、それが役に立たないことですが、含まれているモジュールを完全に制御できる場合は、これが最も簡単な方法です。


fooが未定義の場合、エラーで失敗します。完全に間違っているネイティブプロトタイプを変更することについては触れません。
Kamil Orzechowski

3

ノードv0.11以降、標準のutil関数を使用できます。

var util = require('util');
util.isFunction('foo');

2
util.isFunctionは非推奨
kehers


0

以前のいくつかの回答が示した解決策は、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]();
  }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.