Cách nhận biết hàm JavaScript có được xác định không


302

Làm thế nào để bạn biết nếu một chức năng trong JavaScript được xác định?

Tôi muốn làm một cái gì đó như thế này

function something_cool(text, callback) {
    alert(text);
    if( callback != null ) callback();
}

Nhưng nó mang lại cho tôi một

gọi lại không phải là một chức năng

lỗi khi gọi lại không được xác định.

Câu trả lời:


475
typeof callback === "function"

47
Đây thực sự không phải là một chuỗi ma thuật, vì tập hợp các giá trị typeof được xác định chính xác trong thông số ECMA. Mặc dù cú pháp cho điều này hơi ngớ ngẩn để bắt đầu, nhưng Javascript thành ngữ hoàn toàn hợp lý.
Ben Zotto

2
@quixoto - đã hiểu, tôi đoán điều tôi muốn nói là bạn vẫn cần phải có một chuỗi bất kể - Tôi thà không có bất kỳ chuỗi ký tự nào xả rác mã của tôi hơn là hoàn toàn cần thiết; do đó, đây không phải là lý tưởng của tôi để thử nghiệm nếu một cái gì đó là một chức năng.
Jason Bunting

4
Và vâng, "ma thuật" là một sự lựa chọn từ ngữ cẩu thả, nghèo nàn - ý tôi là "chuỗi chữ" không phải là "chuỗi ma thuật". Lỗi của tôi. :)
Jason Bunting


Đảm bảo xóa dấu ngoặc đơn trên hàm của bạn và chỉ sử dụng tên hàm trong điều kiện if hoặc hàm sẽ được gọi thay vì cung cấp cho bạn đúng hoặc sai.
Russell Strauss

236

Tất cả các câu trả lời hiện tại đều sử dụng một chuỗi ký tự mà tôi không muốn có trong mã của mình nếu có thể - điều này không (và cung cấp ý nghĩa ngữ nghĩa có giá trị, để khởi động):

function isFunction(possibleFunction) {
  return typeof(possibleFunction) === typeof(Function);
}

Cá nhân, tôi cố gắng giảm số lượng chuỗi treo xung quanh trong mã của mình ...


Ngoài ra, trong khi tôi biết rằng đó typeoflà một toán tử chứ không phải là một hàm, có rất ít tác hại trong việc sử dụng cú pháp làm cho nó xuất hiện như là một toán tử sau.


7
Làm thế nào tôi có thể sử dụng chức năng này? Tôi đã thử isFunction(not_defined))not_definedlà tên của chức năng đó không được định nghĩa và Firebug trở not_defined is not definedđó là chính xác nhưng chức năng của bạn nên trả về false và không tạo ra lỗi ...
Wookie88

@ Wookie88: Về mặt kỹ thuật, hàm được minh họa trong câu trả lời của tôi không trả về lỗi nhiều như lỗi xảy ra do trình thông dịch JavaScript đang cố gắng giải quyết biểu tượng not_definedđể chuyển giá trị của nó sang isFunction()và không giải quyết được. Không có gì có thể được thực hiện theo định nghĩa isFunction()để giải quyết vấn đề này.
Jason Bunting

3
@ZacharyYates Cách làm việc xung quanh ReferenceError có nghĩa là tránh làm việc với một tham chiếu đến hàm có thể không được xác định. Bạn có thể thực hiện đánh máy bên trong lệnh gọi hàm và truyền kết quả cho hàm. jsfiddle.net/qNaxJ Có thể không hay lắm, nhưng ít nhất, không có chuỗi nào được sử dụng;)
netiul

8
Hoặc tránh một chức năng isFunctionvà làm chỉ (typeof no_function == typeof Function).
netiul

2
@JasonBunting Nếu bạn sẽ khó tính như vậy, bạn thực sự nên sử dụng typeof(Function())vì Chức năng là một chức năng; nhưng Array, Object và các nguyên mẫu tích hợp khác cũng vậy (vì không có thuật ngữ tốt hơn). Nếu bạn đang kiểm tra một mảng, bạn sẽ không sử dụng typeof(array) === typeof(Array)ví dụ; bạn sẽ sử dụng typeof(array) === typeof(Array())vì bạn thực sự cần đánh giá chức năng nếu bạn cẩn thận và nhất quán.
seanmhanson

16
if (callback && typeof(callback) == "function")

Lưu ý rằng callback (bởi chính nó) đánh giá lại để falsenếu nó là undefined, null, 0, hoặc false. So sánh nulllà quá cụ thể.


2
Cũng lưu ý rằng nếu callbackchính nó ước tính giá trị "false-y", thì kiểu của nó không bao giờ có thể là "hàm".
Joe

5
@Joe, nhưng do đoản mạch, bài kiểm tra đó sẽ không được thực hiện nếu gọi lại đánh giá là sai.
Fabio A.

3
giải pháp này không hiệu quả, vì điều kiện đầu tiên sẽ kích hoạt một ngoại lệ ngay lập tức. điều này có thể hoạt động, đối với một thuộc tính của một đối tượng: if (obj.callback) {...}
Roey

8

Các phương thức này để biết nếu một hàm được triển khai cũng thất bại nếu biến không được xác định, vì vậy chúng tôi đang sử dụng một cái gì đó mạnh hơn hỗ trợ nhận chuỗi:

function isFunctionDefined(functionName) {
    if(eval("typeof(" + functionName + ") == typeof(Function)")) {
        return true;
    }
}

if (isFunctionDefined('myFunction')) {
    myFunction(foo);
}

Tôi nghĩ là một câu trả lời tốt, bạn đã đúng, tất cả các phương pháp trên thất bại là chức năng không được xác định.
Matteo Conta

Thật tầm thường để tránh các tham chiếu không xác định - chỉ cần tham khảo typeof window.doesthisexistthay vì doesthisexist. Tuy nhiên, sử dụng eval (mà: là xấu) như được hiển thị sẽ chỉ hoạt động với các hàm được đặt tên - điều này sẽ không hoạt động với trường hợp sử dụng trong câu hỏi.
AD7six

Xin lưu ý rằng điều này chỉ hoạt động với phạm vi toàn cầu, trong khi câu trả lời được chấp nhận cũng hoạt động với các chức năng phạm vi cục bộ.
inf3rno

6

Mới sử dụng JavaScript Tôi không chắc hành vi đã thay đổi hay chưa nhưng giải pháp được đưa ra bởi Jason Bunting (6 năm trước) sẽ không hoạt động nếu có thể Không xác định được chức năng.

function isFunction(possibleFunction) {
  return (typeof(possibleFunction) == typeof(Function));
}

Điều này sẽ ReferenceError: possibleFunction is not definedgây ra lỗi khi động cơ cố gắng giải quyết biểu tượng có thể Chức năng (như đã đề cập trong các nhận xét cho câu trả lời của Jason)

Để tránh hành vi này, bạn chỉ có thể chuyển tên của hàm bạn muốn kiểm tra nếu nó tồn tại. Vì thế

var possibleFunction = possibleFunction || {};
if (!isFunction(possibleFunction)) return false;

Điều này đặt một biến là hàm bạn muốn kiểm tra hoặc đối tượng trống nếu nó không được xác định và do đó tránh được các vấn đề được đề cập ở trên.


Để hoàn toàn rõ ràng: mã của tôi không gây ra lỗi, đó chỉ là trình phân tích cú pháp JavaScript đang làm điều đó. Điều tương tự sẽ xảy ra nếu bạn cố gắng sử dụng bất kỳ định danh không xác định nào theo cách như vậy.
Jason Bunting

6

Thử:

if (typeof(callback) == 'function')

HI, không sử dụng so sánh "lỏng lẻo" (==) luôn sử dụng '===' để so sánh ngay cả loại biến.
Joel Carneiro

4
function something_cool(text, callback){
    alert(text);
    if(typeof(callback)=='function'){ 
        callback(); 
    };
}

4
if ('function' === typeof callback) ...

3
Một chút pedantic, và vẫn sử dụng một chuỗi bằng chữ. Thế còn if(typeof Function === typeof callback)...? :)
Jason Bunting

@JasonBunting Tò mò, Có gì sai khi sử dụng chuỗi ký tự?
Bsienn

@Bsienn - như tôi đã nói, đó là mô phạm của tôi, nhưng đây là điều. Giả sử bạn sử dụng mã với chuỗi ký tự và lệnh gọi typeoftrả về một cái gì đó khác sau này (có thể là "Hàm" thay vì "hàm"), do cách triển khai JavaScript mới / khác - có vẻ như nó sẽ ít có khả năng hơn việc triển khai mới / khác nhau sẽ phá vỡ typeof Function === typeof callbackkiểm tra vì nó phải giống nhau ở cấp độ ngữ nghĩa.
Jason Bunting


4

Tôi có thể làm

try{
    callback();
}catch(e){};

Tôi biết có một câu trả lời được chấp nhận, nhưng không ai đề xuất điều này. Tôi không thực sự chắc chắn nếu điều này phù hợp với mô tả của thành ngữ, nhưng nó hoạt động cho tất cả các trường hợp.

Trong các công cụ JavaScript mới hơn finallycó thể được sử dụng thay thế.


Đây là một phím tắt gọn gàng! Mặc dù nó sẽ không hoạt động để chỉ kiểm tra nếu một chức năng tồn tại hoặc được xác định (mà không thực hiện nó).
Beejor

Đúng. Tôi giả sử một tình huống trong đó gọi lại là tùy chọn tại điểm thực hiện đó. Tôi thường sử dụng typeof callbackanyway.
Quentin Engles

Điều đó có ý nghĩa; Tôi đã tập trung vào tiêu đề câu hỏi nhiều hơn nội dung của nó. Đôi khi tôi thích sự đơn giản của việc sử dụng thử bắt qua hàng tấn thử nghiệm cho một cái gì đó. Bạn có nghĩ rằng có một bất lợi kỹ thuật khi sử dụng nó, trong trường hợp này so với một cái gì đó như typeof? Hay chủ yếu là vấn đề làm mọi thứ theo cách phù hợp / mong đợi hơn?
Beejor

1
Nếu bạn muốn kiểm tra nhiều loại thì ngoại lệ không tốt lắm. Ví dụ, dự án tôi đang làm việc hiện đang sử dụng rất nhiều kiểu kiểm tra trên một biến để xem đó có phải là hàm, chuỗi hay bất cứ thứ gì không. Trong dự án này tôi thực sự cần các loại. Đối với điều này, tôi sử dụng một loạt các loại và kiểm tra accepted_types.indexOf(typeof value) !== -1xem nó có trong một loạt các loại không. Trong tình huống này, ngoại lệ sẽ bị cấm theo ý kiến ​​của tôi.
Quentin Engles

2

Thử cái này:

callback instanceof Function

1
Không hoạt động. Nó vẫn sẽ cung cấp cho bạn lỗi. Bạn nên tự mình thử trước khi đăng nó như một câu trả lời.
vbullinger

@vbullinger Tôi vừa thử nghiệm lại trong Chrome, Firefox và Safari - hoạt động ở mọi nơi. Với động cơ nào bạn đã gặp sự cố?
eWolf

Firefox. Bạn đã kiểm tra trường hợp khi gọi lại không được xác định?
vbullinger

Đó là bởi vì bạn đang trực tiếp tham chiếu một biến không xác định, không bao giờ hoạt động: pastebin.com/UQz2AmzH
eWolf

3
Nó hoạt động khi được sử dụng trên một tham số chức năng, đó là những gì tác giả yêu cầu - Tôi cho rằng ECMAScript phân biệt các trường hợp của một biến không tồn tại và một biến hiện có với giá trị không xác định. Sẽ rất thú vị khi biết thêm về điều này.
eWolf

2

Nếu bạn nhìn vào nguồn của thư viện @Venkat Sudheer Reddy Aedama đã đề cập, gạch dưới, bạn có thể thấy điều này:

_.isFunction = function(obj) {
  return typeof obj == 'function' || false;
};

Đây chỉ là câu trả lời GỢI Ý, GỢI Ý của tôi:>


2

Thử:

if (!(typeof(callback)=='undefined')) {...}


1

Tôi đang tìm cách kiểm tra xem hàm jQuery có được xác định không và tôi không tìm thấy nó dễ dàng.

Có lẽ có thể cần nó;)

if(typeof jQuery.fn.datepicker !== "undefined")

tương tự như type0f($.datepicker) !== undefiledcách khác sẽ làobject
vladkras

0

Nếu callback()bạn đang gọi không chỉ một lần trong một hàm, bạn có thể khởi tạo đối số để sử dụng lại:

callback = (typeof callback === "function") ? callback : function(){};

Ví dụ:

function something_cool(text, callback) {
    // Initialize arguments
    callback = (typeof callback === "function") ? callback : function(){};

    alert(text);

    if (text==='waitAnotherAJAX') {
        anotherAJAX(callback);
    } else {
        callback();
    }
}

Hạn chế là nó sẽ luôn thực thi đối số gọi lại mặc dù nó không được xác định.


0

Đối với các hàm toàn cầu, bạn có thể sử dụng hàm này thay vì được evalđề xuất trong một trong các câu trả lời.

var global = (function (){
    return this;
})();

if (typeof(global.f) != "function")
    global.f = function f1_shim (){
        // commonly used by polyfill libs
    };

Bạn có thể sử dụng global.f instanceof Functionlà tốt, nhưng afaik. giá trị của Functionsẽ khác nhau trong các khung khác nhau, vì vậy nó sẽ chỉ hoạt động với một ứng dụng khung duy nhất đúng cách. Đó là lý do tại sao chúng ta thường sử dụng typeofthay thế. Lưu ý rằng trong một số môi trường cũng có thể có sự bất thường typeof f, ví dụ như MSIE 6-8, một số chức năng chẳng hạnalert có loại "đối tượng".

Bằng các hàm cục bộ, bạn có thể sử dụng một trong câu trả lời được chấp nhận. Bạn có thể kiểm tra xem chức năng là cục bộ hay toàn cầu.

if (typeof(f) == "function")
    if (global.f === f)
        console.log("f is a global function");
    else
        console.log("f is a local function");

Để trả lời câu hỏi, mã ví dụ đang hoạt động với tôi mà không có lỗi trong các trình duyệt mới nhất, vì vậy tôi không chắc vấn đề với nó là gì:

function something_cool(text, callback) {
    alert(text);
    if( callback != null ) callback();
}

Lưu ý: Tôi sẽ sử dụng callback !== undefinedthay vì callback != null, nhưng chúng làm gần như nhau.


0

Hầu hết nếu không phải tất cả các câu trả lời trước đều có tác dụng phụ để gọi hàm

ở đây thực hành tốt nhất

bạn có chức năng

function myFunction() {
        var x=1;
    }
cách trực tiếp để kiểm tra nó

//direct way
        if( (typeof window.myFunction)=='function')
            alert('myFunction is function')
        else
            alert('myFunction is not defined');
sử dụng một chuỗi để bạn chỉ có một nơi để xác định tên hàm

//byString
        var strFunctionName='myFunction'
        if( (typeof window[strFunctionName])=='function')
            alert(s+' is function');
        else
            alert(s+' is not defined');


0

Nếu bạn muốn xác định lại các hàm, tốt nhất là sử dụng các biến hàm, được xác định theo thứ tự xuất hiện của chúng, vì các hàm được xác định trên toàn cầu, bất kể chúng xuất hiện ở đâu.

Ví dụ về việc tạo một hàm mới gọi một hàm trước đó có cùng tên:

A=function() {...} // first definition
...
if (typeof A==='function')
   oldA=A;
A=function() {...oldA()...} // new definition

0

Điều này làm việc cho tôi

if( cb && typeof( eval( cb ) ) === "function" ){
    eval( cb + "()" );
}

-2

Giải pháp một dòng:

function something_cool(text, callback){
    callback && callback();
}

Ví dụ của anh ta cho thấy rằng anh ta muốn gọi hàm nếu nó được xác định và nếu không, không có gì xảy ra. jsfiddle.net/nh1cxxg6 Các hàm trả về giá trị falsey / false vẫn được gọi. Tất nhiên, điều này không hoạt động khi bạn muốn các giá trị được trả về.
Samir Alajmovic

Ah, tôi đọc sai câu hỏi của anh ấy. Tuy nhiên, điều này sẽ gây ra ngoại lệ nếu gọi lại không phải là một chức năng.
Frank Bryce
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.