回答:
確かにアンダースコアの方が効率的ですが、効率が問題でない場合にチェックする最良の方法は、@ Paul Rosaniaによってリンクされたアンダースコアのページに書かれています。
下線に触発された最終的なisFunction関数は次のとおりです。
function isFunction(functionToCheck) {
return functionToCheck && {}.toString.call(functionToCheck) === '[object Function]';
}
isFunctionA
は、他の方法と比較した実装の違いを示しています。
typeof(obj) === 'function'
、最速のようです。ただし、Firefoxではobj instanceof Function
明らかに勝者です。
if (typeof v === "function") {
// do something
}
typeof Object
、typeof Date
およびtypeof String
、そのすべての戻り'function'
すぎ。
if (v instanceOf Function)
ますか?
instanceof
が、別のドキュメント(iframeなど)の関数をチェックしている場合は機能しません。パフォーマンスはさまざまです。
asyncfunctionToCheck
、 getType.toString.call(functionToCheck)==='[object AsyncFunction]'
ここでtypeof asyncfunctionToCheck === 'function'
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
か?
typeof == "function"
)。Underscore の「高速」バージョンよりもはるかに高速のようです。
isFunction()
。それは現在、ダンデーンが示唆したものに非常に近いものを使用しています。
いくつかの方法があるので、それらすべてを要約します
function foo(v){if(v instanceof Function){/ *何かをする* /}};ほとんどのパフォーマンス(文字列比較なし)でエレガントなソリューション-instanceof演算子はブラウザーで非常に長い間サポートされているので、心配しないでください-IE 6で動作します。
function foo(v){if(typeof v === "function"){/ *何かをする* /}};不利な点
typeof
は、サイレントエラーの影響を受けやすいことです。悪いため、タイプミスがある場合(たとえば、「finction」)-この場合、 `if`はfalseを返すだけで、後でエラーが発生することがわかりますあなたのコード
function isFunction(functionToCheck){ var getType = {}; return functionToCheck && getType.toString.call(functionToCheck)=== '[オブジェクト関数]'; }これは、ソリューション#1または#2に勝る利点はありませんが、読みにくくなります。これの改良版は
function isFunction(x){ return Object.prototype.toString.call(x)== '[オブジェクト関数]'; }しかし、ソリューション#1よりもセマンティックがはるかに少ない
top.Function !== Function
。確かに、2番目のものを使用してください(「関数」のスペルミスはデバッグ中に修正されると幸いです)。
instanceof
、フレーム全体のチェックなどの複数のグローバルを考慮せず、偽陰性を返す可能性があります。
@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
より多くのブラウザーサポートがあり、非同期関数も含まれているものは次のとおりです。
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
他の簡単な方法:
var fn = function () {}
if (fn.constructor === Function) {
// true
} else {
// false
}
fn && fn.constructor === Function
これはどう?
関数型に興味がある、またはメタプログラミング(型チェックなど)で利用するためのより表現力豊かなアプローチを探している人にとって、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);
もちろん、関数を「安全」にするには、関数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 ));
ただし、このソリューションでは、高次関数が頻繁に使用されるため、他の利用可能なオプションよりもパフォーマンスが低下する可能性があることに注意してください。
私は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以下ではこれが常に機能するとは限らないことをどこかで読んだことがあります。
以下も私にとってはうまくいくようです(からテストされましたnode.js
):
var isFunction = function(o) {
return Function.prototype.isPrototypeOf(o);
};
console.log(isFunction(function(){})); // true
console.log(isFunction({})); // false
関数プロトタイプにフラグを定義して、テストするインスタンスがそれを継承しているかどうかを確認するだけでよいと思います
フラグを定義します。
Function.prototype.isFunction = true;
それが存在するかどうかを確認します
var foo = function(){};
foo.isFunction; // will return true
欠点は、別のプロトタイプが同じフラグを定義でき、それが役に立たないことですが、含まれているモジュールを完全に制御できる場合は、これが最も簡単な方法です。