javascript - Sjekk om en variabel er av funksjonstype


Anta at jeg har en hvilken som helst variabel, som er definert som følger:

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

Jeg vil ha en funksjon som sjekker om typen til variabelen er funksjonslignende. dvs. :

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

Hvordan kan jeg sjekke om variabelen a er av typen Function på den måten som er definert ovenfor?

Svar #1

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

Svar #2

Selvfølgelig er underscorens metode mer effektiv, men den beste måten å sjekke på, når effektivitet ikke er et problem, er skrevet på underscores side lenket av @Paul Rosania.

Inspirert av underscore, er den endelige isFunction-funksjonen som følger:

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

Merk: Denne løsningen fungerer ikke for asynkrone funksjoner, generatorer eller proxy-funksjoner. Vennligst se andre svar for mer oppdaterte løsninger.

Svar #3

Det er flere måter, så jeg vil oppsummere dem alle

  1. Beste måten er:

    function foo(v) {if (v instanceof Function) {/* do something */} };
    

    Mest ytelsessterk (ingen strengsammenligning) og elegant løsning - instanceof-operatoren har vært støttet i nettlesere i veldig lang tid, så ikke bekymre deg - den vil fungere i IE 6.

  2. Neste beste måte er:

    function foo(v) {if (typeof v === "function") {/* do something */} };
    

    Ulempen med typeof er at det er utsatt for stille feil, dårlig, så hvis du har en skrivefeil (f.eks. "finction") - i dette tilfellet vil if bare returnere false og du vil ikke vite at du har en feil før senere i koden din

  3. Den neste beste måten er:

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

    Dette har ingen fordel sammenlignet med løsning #1 eller #2, men er mye mindre lesbart. En forbedret versjon av dette er

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

    men fortsatt mye mindre semantisk enn løsning #1

Svar #4

Underscore.js bruker en mer utsmykket, men svært effektiv test:

_.isFunction = function(obj) {
  return !!(obj && obj.constructor && obj.call && obj.apply);
};

Se: https://jsben.ch/B6h73

REDIGER: oppdaterte tester antyder at typeof kan være raskere, se https://jsben.ch/B6h73

Svar #5

jQuery (utfaset siden versjon 3.3) Referanse

$.isFunction(functionName);

AngularJS Referanse

angular.isFunction(value);

Lodash Referanse

_.isFunction(value);

Understrek Referanse

_.isFunction(object); 

Node.js avskrevet siden v4.0.0 Referanse

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

Svar #6

@grandecomplex: Det er en god del ord på løsningen din. Det ville vært mye tydeligere om det ble skrevet slik:

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

Svar #7

Noe med mer nettleserstøtte og som også inkluderer asynkrone funksjoner kunne være:

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

og test det deretter slik:

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

Svar #8

const foo = function() {};
if (typeof foo === 'function') {
  console.log('is function')
}

Svar #9

Prøv instanceof-operatoren: det ser ut til at alle funksjoner arver fra Function-klassen:

// 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

Svar #10

En annen enkel måte:

var fn = function () {}
if (fn.constructor === Function) {
  // true
} else {
  // false
}

Svar #11

For de som er interessert i funksjonell stil, eller ser etter en mer uttrykksfull tilnærming å bruke i metaprogrammering (som typekontroll), kan det være interessant å se på Ramda-biblioteket for å utføre en slik oppgave.

Neste kode inneholder kun rene og pointfree-funksjoner:

const R = require('ramda');

const isPrototypeEquals = R.pipe(Object.getPrototypeOf, R.equals);

const equalsSyncFunction = isPrototypeEquals(() => {});

const isSyncFunction = R.pipe(Object.getPrototypeOf, equalsSyncFunction);

Fra og med ES2017 er async-funksjoner tilgjengelige, så vi kan sjekke mot dem også:

const equalsAsyncFunction = isPrototypeEquals(async () => {});

const isAsyncFunction = R.pipe(Object.getPrototypeOf, equalsAsyncFunction);

Og så kombinerer du dem sammen:

const isFunction = R.either(isSyncFunction, isAsyncFunction);

Selvfølgelig bør funksjonen beskyttes mot null og undefined-verdier, så for å gjøre den «sikker»:

const safeIsFunction = R.unless(R.isNil, isFunction);

Og, komplett utsnitt for å oppsummere:

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

Merk imidlertid at denne løsningen kan vise lavere ytelse enn andre tilgjengelige alternativer på grunn av omfattende bruk av høyereordensfunksjoner.

Relaterte artikler