Kiểm tra xem một biến có thuộc loại chức năng không


904

Giả sử tôi có bất kỳ biến nào, được định nghĩa như sau:

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

Tôi muốn một hàm kiểm tra xem loại của biến có giống như hàm không. I E :

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

Làm cách nào để kiểm tra xem biến acó thuộc loại Functionđược xác định ở trên không?


2
đây là điểm chuẩn cho những cách phổ biến nhất này để kiểm tra jsben.ch/#/e5Ogr
EscapeNetscape

Câu trả lời:


380

Chắc chắn cách gạch dưới là hiệu quả hơn, nhưng cách tốt nhất để kiểm tra, khi hiệu quả không phải là vấn đề, được viết trên trang gạch dưới được liên kết bởi @Paul Rosania.

Lấy cảm hứng từ gạch dưới, chức năng isFactor cuối cùng như sau:

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

1
Có thể có ai đó đã thực hiện nghiên cứu sâu rộng hơn về vấn đề này, nhưng hãy xem kết quả sửa đổi 4 của jsperf với "xác minh kết quả" đơn giản . isFunctionAcho thấy một sự khác biệt thực hiện so với các phương pháp khác.
Joel Purra

24
Với các bài kiểm tra hiệu suất được cập nhật, có vẻ như có sự khác biệt lớn về tốc độ tùy thuộc vào trình duyệt của bạn. Trong Chrome typeof(obj) === 'function'dường như là nhanh nhất cho đến nay; tuy nhiên, trong Firefox obj instanceof Functionlà người chiến thắng rõ ràng.
Justin Warkentin

7
Về phần: typeof chỉ nên được sử dụng để kiểm tra nếu các biến hoặc thuộc tính không được xác định. Tại javascript.info/tutorial/type-detection trong phần Sử dụng tốt phần typeof và phần sau đây của tác giả, trường hợp này hoàn toàn ngược lại
Konrad Madej

11
Alex, tôi tò mò tại sao bạn nói typeof chỉ nên được sử dụng để kiểm tra không xác định. Tên của nó cho thấy mục đích của nó là kiểm tra loại của một cái gì đó, không chỉ là nó có tồn tại hay không. Có vấn đề kỹ thuật hoặc vấn đề có thể phát sinh khi sử dụng nó để kiểm tra loại, hoặc nó là một ưu tiên? Nếu có sự cẩn thận, sẽ tốt khi liệt kê chúng để những người khác có thể tránh vấp ngã.
jinglểula

14
giải pháp quá phức tạp một cách vô lý
Daniel Garmoshka

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

44
Chỉ cần xem ra cho một vài điều như typeof Object, typeof Datetypeof String, mà tất cả trở lại 'function'quá.
Dave Ward

358
@Dave, tôi không chắc vấn đề là gì vì đó là các chức năng.
Matthew Crumley

6
Sự khác biệt với là if (v instanceOf Function)gì?
mquandalle

10
@mquandalle Không có sự khác biệt lớn, ngoại trừ instanceofsẽ không hoạt động nếu bạn đang kiểm tra một chức năng đến từ một tài liệu khác (iframe, có thể). Hiệu suất khác nhau.
rvighne

8
không giống như câu trả lời được chấp nhận, nó cũng hoạt động cho các chức năng async. Đối với một asyncfunctionToCheck, getType.toString.call(functionToCheck)==='[object AsyncFunction]'nơi nhưtypeof asyncfunctionToCheck === 'function'
TDreama

132

Underscore.js sử dụng một bài kiểm tra phức tạp hơn nhưng hiệu suất cao hơn:

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

Xem: http://jsperf.com/alternative-isfeft-im THỰCations

EDIT: các thử nghiệm được cập nhật cho thấy typeof có thể nhanh hơn, xem http://jsperf.com/alternative-isfeft-im THỰCations / 4


Có bất kỳ lý do cụ thể để sử dụng phương pháp này hơn typof?
sv_in

1
Phiên bản của Underscore nhanh hơn nhiều trong hầu hết các trình duyệt. Xem: jsperf.com/alternative-isfeft-im THỰCations
Paul Rosania

13
Tôi chắc chắn thích thích gạch dưới, đơn giản nhưng mạnh mẽ. Điều đó nói rằng, có lẽ đáng lưu ý rằng việc thực hiện này có thể bị giả mạo bởi một đối tượng có các thuộc tính đó.
studgeek

3
@PaulRosania Tình cờ gặp các bài kiểm tra hiệu suất này sớm hôm nay và cập nhật chúng với xác minh cộng với nhiều dữ liệu kiểm tra hơn như phiên bản 4 - vui lòng chạy nó để tăng phạm vi kiểm tra trình duyệt. Tốc độ hoạt động chậm hơn mỗi giây (do có nhiều thử nghiệm), nhưng nó cũng cho thấy một sự khác biệt khi triển khai (mở bảng điều khiển javascript của bạn và tải lại trang, có thể có thông báo lỗi được ghi lại). Lưu ý: Bản sửa đổi 3 đã thêm isFunctionD (chỉ dựa trên typeof == "function") - và dường như nhanh hơn nhiều so với phiên bản "nhanh" của Underscore.
Joel Purra

6
Câu trả lời này bây giờ hơi sai lệch, vì Underscore.js hiện đang ở phiên bản 12 , không phải là phiên bản 4 được tham chiếu ở trên, về thử nghiệm thay thế của nó isFunction(). Nó hiện đang sử dụng một cái gì đó rất gần với những gì dandean đề xuất.
Jonathan Eunice

112

Có một số cách vì vậy tôi sẽ tóm tắt tất cả

  1. Cách tốt nhất là:
    hàm foo (v) {if (v instanceof Hàm) {/ * làm gì đó * /}};
    
    
    Hầu hết hiệu năng (không so sánh chuỗi) và giải pháp tao nhã - toán tử instanceof đã được hỗ trợ trong các trình duyệt trong một thời gian rất dài, vì vậy đừng lo lắng - nó sẽ hoạt động trong IE 6.
  2. Cách tốt nhất tiếp theo là:
    hàm foo (v) {if (typeof v === "function") {/ * làm gì đó * /}};
    
    
    Nhược điểm của typeofnó là dễ bị lỗi im lặng, xấu, vì vậy nếu bạn mắc lỗi đánh máy (ví dụ: "fifying") - trong trường hợp này, `if` sẽ trả về sai và bạn sẽ không biết mình có lỗi cho đến sau này ma cua ban
  3. Cách tốt nhất tiếp theo là:
    Hàm isFunction (functionToCheck) {
        var getType = {};
        return functionToCheck && getType.toString.call (functionToCheck) === '[Hàm đối tượng]';
    }
    
    
    Điều này không có lợi thế so với giải pháp số 1 hoặc số 2 nhưng ít đọc hơn nhiều. Một phiên bản cải tiến của điều này là
    hàm isFunction (x) {
        return Object.prototype.toString.call (x) == '[Hàm đối tượng]';
    }
    
    
    nhưng vẫn còn ít ngữ nghĩa hơn giải pháp số 1

10
Giải pháp đầu tiên thất bại trong trường hợp một chức năng được chuyển đến bối cảnh khung khác. Ví dụ: từ iframe top.Function !== Function. Để chắc chắn, sử dụng cái thứ hai (bất kỳ lỗi chính tả nào của "hàm" sẽ được sửa trong quá trình gỡ lỗi, hy vọng).
MaxArt

Về quan điểm của bạn về lỗi chính tả: bất kỳ mã nào có lỗi đánh máy này đều có khả năng bị lỗi nhanh chóng / không rõ ràng hơn bất kỳ lỗi nào khác dựa trên lỗi chính tả. typeof === "chức năng" là giải pháp sạch nhất. Ngoài ra, giải pháp tốt nhất của bạn, nơi bạn sử dụng instanceofkhông tính đến nhiều toàn cầu, chẳng hạn như kiểm tra trên các khung và có thể trả về các phủ định sai.
brainkim


56

@grandecomplex: Có một lượng dài bằng lời cho giải pháp của bạn. Sẽ rõ ràng hơn nhiều nếu được viết như thế này:

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

Object.prototype.toString.call rất hữu ích cho các loại javascript khác mà bạn quan tâm. Thậm chí bạn có thể kiểm tra chống lại null hoặc không xác định, điều này làm cho nó rất mạnh mẽ.
Jason Foglia

49

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


1
... Và (() => (typeof obj === 'function') && doSomething())vẫn là lựa chọn nhanh nhất.
darcher

35

Hãy thử instanceoftoán tử: có vẻ như tất cả các hàm kế thừa từ Functionlớp:

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

Một cái gì đó có nhiều hỗ trợ trình duyệt hơn và cũng bao gồm các chức năng async có thể là:

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

và sau đó kiểm tra nó như sau:

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

11

Một cách khác đơn giản:

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

1
nếu fn sẽ không được xác định, nó sẽ xuất hiện Lỗi
Kamil Or817owski

fn && fn.constructor === Function Còn cái này thì sao?
Yar Tư Melnichuk

9

Đối với những người quan tâm đến phong cách chức năng, hoặc tìm kiếm cách tiếp cận biểu cảm hơn để sử dụng trong lập trình meta (chẳng hạn như kiểm tra kiểu), thật thú vị khi xem Ramda thư viện thực hiện nhiệm vụ đó.

Mã tiếp theo chỉ chứa các hàm thuần túy và không có điểm:

const R = require('ramda');

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

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

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

Kể từ ES2017, các asyncchức năng cũng có sẵn, vì vậy chúng tôi cũng có thể kiểm tra lại chúng:

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

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

Và sau đó kết hợp chúng lại với nhau:

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

Tất nhiên, chức năng nên được bảo vệ chống lại nullundefinedcác giá trị, vì vậy để làm cho nó "an toàn":

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

Và, hoàn thành đoạn trích để tổng hợp:

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

Tuy nhiên, lưu ý rằng giải pháp này có thể hiển thị ít hiệu suất hơn các tùy chọn khả dụng khác do sử dụng rộng rãi các chức năng bậc cao hơn.


7

Nếu bạn sử dụng Lodash, bạn có thể làm điều đó với _.isFunction .

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

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

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

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

Phương thức này trả về truenếu giá trị là một hàm, khác false.


4

Tôi thấy rằng khi kiểm tra chức năng trình duyệt có nguồn gốc trong IE8, sử dụng toString, instanceoftypeofkhông làm việc. Đây là một phương pháp hoạt động tốt trong IE8 (theo như tôi biết):

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

Ngoài ra, bạn có thể kiểm tra các chức năng gốc bằng cách sử dụng:

"getElementById" in document

Mặc dù vậy, tôi đã đọc được ở đâu đó rằng điều này sẽ không luôn luôn hoạt động trong IE7 trở xuống.


4

Dưới đây dường như cũng làm việc cho tôi (được thử nghiệm từ node.js):

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

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

4

Tôi nghĩ rằng bạn chỉ có thể xác định một cờ trên nguyên mẫu Hàm và kiểm tra xem trường hợp bạn muốn kiểm tra có kế thừa không

xác định một cờ:

Function.prototype.isFunction = true; 

và sau đó kiểm tra nếu nó tồn tại

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

Nhược điểm là một nguyên mẫu khác có thể định nghĩa cùng một cờ và sau đó nó vô dụng, nhưng nếu bạn có toàn quyền kiểm soát các mô-đun đi kèm thì đó là cách dễ nhất


Nó sẽ thất bại với Lỗi nếu foo không được xác định. Không đề cập đến việc bạn sửa đổi nguyên mẫu bản địa đó là hoàn toàn sai.
Kamil Or817owski

3

Vì nút v0.11, bạn có thể sử dụng chức năng sử dụng tiêu chuẩn:

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

2
produc.isFunction bị phản đối
kehers

2

bạn nên sử dụng typeOftoán tử trong js.

var a=function(){
    alert("fun a");
}
alert(typeof a);// alerts "function"

0

Giải pháp như một số câu trả lời trước đây đã chỉ ra là sử dụng typeof. sau đây là đoạn mã trong 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]();
  }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.