จะทราบได้อย่างไรว่ามีการกำหนดฟังก์ชัน JavaScript หรือไม่


302

คุณจะทราบได้อย่างไรว่ามีการกำหนดฟังก์ชันใน JavaScript หรือไม่

ฉันต้องการทำอะไรแบบนี้

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

แต่มันทำให้ฉันได้รับ

โทรกลับไม่ใช่ฟังก์ชั่น

ข้อผิดพลาดเมื่อไม่ได้กำหนดโทรกลับ

คำตอบ:


475
typeof callback === "function"

47
นี่ไม่ใช่สตริงมายากลเนื่องจากชุดของค่าประเภทถูกกำหนดไว้อย่างแม่นยำในข้อมูลจำเพาะ ECMA แม้ว่าไวยากรณ์สำหรับสิ่งนี้จะเริ่มต้นเล็กน้อย แต่ก็มีจาวาสคริปต์ที่มีเหตุผล
Ben Zotto

2
@quixoto - เข้าใจแล้วฉันเดาว่าฉันหมายถึงอะไรนั่นก็คือคุณยังต้องมีสตริงโดยไม่คำนึงถึง - ฉันอยากจะไม่มีตัวอักษรที่มากกว่าที่ทำให้รหัสของฉันเกลื่อนไปกว่าที่จำเป็นจริงๆ ดังนั้นนี่ไม่ใช่ของฉันที่เหมาะสำหรับการทดสอบว่ามีฟังก์ชั่นอะไร
เจสันตอม่อ

4
และใช่ "เวทมนต์" เป็นตัวเลือกคำที่เลอะเทอะและไม่ดี - ฉันหมายถึง "สตริงตัวอักษร" ไม่ใช่ "เวทสตริง" ความผิดฉันเอง. :)
Jason Bunting


ตรวจสอบให้แน่ใจว่าได้ลบวงเล็บบนฟังก์ชันของคุณและใช้ชื่อฟังก์ชันใน if-condition หรือฟังก์ชันจะถูกเรียกใช้แทนการให้คุณจริงหรือเท็จ
รัสเซลสเตราส์

236

คำตอบปัจจุบันทั้งหมดใช้สตริงตัวอักษรซึ่งฉันไม่ต้องการให้มีในรหัสถ้าเป็นไปได้ - นี่ไม่ได้ (และให้ความหมายเชิงความหมายที่มีคุณค่าในการบูต):

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

โดยส่วนตัวฉันพยายามลดจำนวนสตริงที่ห้อยอยู่ในรหัสของฉัน ...


นอกจากนี้ในขณะที่ฉันรู้ว่าtypeofเป็นตัวดำเนินการและไม่ใช่ฟังก์ชั่นมีความเสียหายเล็กน้อยในการใช้ไวยากรณ์ที่ทำให้ดูเหมือนเป็นหลัง


7
ฉันควรจะใช้ฟังก์ชั่นนี้ได้อย่างไร? ฉันได้พยายามisFunction(not_defined))ที่not_definedเป็นชื่อของฟังก์ชั่นที่ไม่ได้กำหนดและ FireBug กลับnot_defined is not definedซึ่งเป็นที่ถูกต้อง แต่การทำงานของคุณควรกลับเท็จและไม่สร้างข้อผิดพลาด ...
Wookie88

@ Wookie88: การพูดทางเทคนิคฟังก์ชั่นที่แสดงในคำตอบของฉันไม่ได้ส่งคืนข้อผิดพลาดมากนักเนื่องจากมีข้อผิดพลาดเกิดขึ้นเนื่องจากล่าม JavaScript พยายามแก้ไขสัญลักษณ์not_definedเพื่อส่งผ่านค่าของมันisFunction()และไม่สามารถแก้ไขได้ ไม่สามารถทำอะไรได้เพื่อนิยามของisFunction()การแก้ปัญหานี้
เจสันตอม่อ

3
@ZacharyYates วิธีการแก้ไข ReferenceError จะหมายถึงการหลีกเลี่ยงการทำงานกับการอ้างอิงถึงฟังก์ชันที่อาจไม่ได้กำหนดไว้ คุณสามารถพิมพ์ตัวตรวจสอบภายในการเรียกใช้ฟังก์ชันและส่งผลลัพธ์ไปยังฟังก์ชัน jsfiddle.net/qNaxJอาจจะไม่ดีนัก แต่อย่างน้อยก็ไม่มีการใช้สตริง;)
netiul

8
หรือหลีกเลี่ยงการทำงานและทำเพียงแค่isFunction (typeof no_function == typeof Function)
netiul

2
@ JasonBunting หากคุณจะเป็นคนพิถีพิถันคุณควรใช้ typeof(Function())เพราะ Function เป็นหน้าที่; แต่เช่นนั้นก็คืออาเรย์, วัตถุและต้นแบบอื่น ๆ ในตัว (สำหรับการขาดคำที่ดีกว่า) หากคุณกำลังตรวจสอบอาร์เรย์คุณจะไม่ใช้typeof(array) === typeof(Array)ตัวอย่างเช่น คุณจะใช้typeof(array) === typeof(Array())เพราะคุณจำเป็นต้องประเมินฟังก์ชั่นถ้าคุณระมัดระวังและสอดคล้องกัน
seanmhanson

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

โปรดทราบว่าการโทรกลับ (ด้วยตัวเอง) ประเมินfalseถ้ามันเป็นundefined, null, หรือ0 falseเปรียบเทียบกับnullเฉพาะเจาะจงมากเกินไป


2
นอกจากนี้โปรดทราบว่าหากcallbackตัวเองประเมินเป็นค่า "false-y" ประเภทของมันจะไม่เป็น "ฟังก์ชัน"
Joe

5
@ Joe แต่เนื่องจากการลัดวงจรการทดสอบนั้นจะไม่สามารถดำเนินการได้หากการเรียกกลับประเมินว่าเป็นเท็จ
Fabio A.

3
วิธีนี้ไม่ทำงานเนื่องจากเงื่อนไขแรกจะเริ่มข้อยกเว้นทันที สิ่งนี้อาจใช้งานได้สำหรับคุณสมบัติของวัตถุ: if (obj.callback) {... }
Roey

8

วิธีการเหล่านั้นเพื่อบอกว่าฟังก์ชั่นการใช้งานยังล้มเหลวหากไม่ได้กำหนดตัวแปรดังนั้นเราจึงใช้บางอย่างที่มีประสิทธิภาพมากกว่าที่รองรับการรับสาย:

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

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

ฉันคิดว่าเป็นคำตอบที่ดีคุณพูดถูกวิธีทั้งหมดข้างต้นล้มเหลวคือฟังก์ชั่นไม่ได้กำหนดไว้
Matteo Conta

มันเป็นเรื่องเล็ก ๆ น้อย ๆ เพื่อหลีกเลี่ยงการอ้างอิงที่ไม่ได้กำหนด - เพียงหมายถึงการแทนtypeof window.doesthisexist doesthisexistอย่างไรก็ตามการใช้ eval (ซึ่ง: เป็นสิ่งที่ชั่วร้าย) ดังที่แสดงจะใช้งานได้กับฟังก์ชั่นที่ตั้งชื่อเท่านั้น - สิ่งนี้จะไม่ทำงานกับกรณีการใช้งานในคำถาม
AD7six

โปรดทราบว่าสิ่งนี้ใช้ได้กับขอบเขตทั่วโลกเท่านั้นในขณะที่คำตอบที่ยอมรับนั้นใช้งานได้กับฟังก์ชั่นขอบเขตท้องถิ่นเช่นกัน
inf3rno

6

ใหม่สำหรับ JavaScript ฉันไม่แน่ใจว่าพฤติกรรมมีการเปลี่ยนแปลงหรือไม่ แต่โซลูชันที่ Jason Bunting ให้ (6 ปีที่แล้ว) ไม่ทำงานหากไม่ได้กำหนดฟังก์ชันที่เป็นไปได้

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

นี้จะโยน ReferenceError: possibleFunction is not definedข้อผิดพลาดในขณะที่เอ็นจินพยายามแก้ไขสัญลักษณ์ที่เป็นไปได้ฟังก์ชั่น (ดังที่กล่าวไว้ในความคิดเห็นต่อคำตอบของเจสัน)

เพื่อหลีกเลี่ยงพฤติกรรมนี้คุณสามารถส่งชื่อฟังก์ชั่นที่คุณต้องการตรวจสอบว่ามีอยู่หรือไม่ ดังนั้น

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

ชุดนี้ตัวแปรจะเป็นฟังก์ชั่นที่คุณต้องการตรวจสอบหรือวัตถุที่ว่างเปล่าถ้ามันไม่ได้กำหนดและเพื่อหลีกเลี่ยงปัญหาดังกล่าวข้างต้น


เพื่อความชัดเจนอย่างสมบูรณ์: รหัสของฉันไม่ได้ทิ้งข้อผิดพลาดนั่นเป็นเพียงตัวแยกวิเคราะห์ JavaScript ที่ทำเช่นนั้น เช่นเดียวกันจะเกิดขึ้นหากคุณพยายามใช้ตัวระบุที่ไม่ได้กำหนดในลักษณะดังกล่าว
Jason Bunting

6

ลอง:

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

สวัสดีอย่าใช้การเปรียบเทียบแบบ "หลวม" (==) ใช้ '===' เสมอเพื่อเปรียบเทียบแม้กระทั่งชนิดของตัวแปร
Joel Carneiro


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

3
บิตอวดความรู้และยังคงใช้ตัวอักษรสตริง แล้วไงif(typeof Function === typeof callback)...ล่ะ :)
Jason Bunting

@ JasonBunting อยากรู้อยากเห็นเกิดอะไรขึ้นกับการใช้สตริงตัวอักษร?
Bsienn

@Bsienn - อย่างที่ฉันพูดมันเป็นเรื่องอื้อฉาวของฉัน แต่นี่คือสิ่งที่ สมมติว่าคุณใช้รหัสที่มีตัวอักษรสตริงและการเรียกร้องให้typeofผลตอบแทนบางสิ่งบางอย่างที่แตกต่างกันไป (อาจจะ "ฟังก์ชั่น" แทน "ฟังก์ชั่น") เนื่องจากการดำเนินงานใหม่ / แตกต่างกันของ JavaScript - มันรู้สึกเหมือนมันจะมีโอกาสน้อยที่ การนำไปใช้ใหม่ / ที่แตกต่างกันจะทำให้การtypeof Function === typeof callbackตรวจสอบแตกหักเพราะมันควรจะเหมือนกันในระดับความหมาย
Jason Bunting


4

ฉันอาจทำ

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

ฉันรู้ว่ามีคำตอบที่ยอมรับได้ แต่ไม่มีใครแนะนำสิ่งนี้ ฉันไม่แน่ใจว่านี่เหมาะกับคำอธิบายของสำนวนหรือไม่ แต่มันใช้ได้กับทุกกรณี

ในเอ็นจิน JavaScript ที่ใหม่กว่าfinallyสามารถใช้แทนได้


นี่เป็นทางลัดที่เรียบร้อย! แม้ว่ามันจะไม่ทำงานสำหรับการทดสอบเพียงอย่างเดียวหากมีฟังก์ชั่นอยู่หรือถูกกำหนดไว้
Beejor

นั่นเป็นเรื่องจริง ฉันสันนิษฐานว่าเป็นสถานการณ์ที่การติดต่อกลับเป็นตัวเลือกที่จุดดำเนินการนั้น ฉันมักจะใช้typeof callbackต่อไป
Quentin Engles

นั่นทำให้รู้สึก; ฉันมุ่งเน้นไปที่ชื่อคำถามมากกว่าเนื้อหา บางครั้งฉันชอบความเรียบง่ายในการใช้การทดสอบมากกว่าหลายครั้ง คุณคิดว่ามีข้อเสียทางเทคนิคหรือไม่ที่จะใช้มันในกรณีนี้กับบางอย่างเช่นประเภทของ? หรือว่าเป็นเรื่องของการทำสิ่งต่าง ๆ ในแบบที่เหมาะสมกว่าที่คาดไว้?
Beejor

1
หากคุณต้องการทดสอบหลายประเภทข้อยกเว้นจะไม่ดี ตัวอย่างเช่นโครงการที่ฉันกำลังทำอยู่ตอนนี้ใช้การตรวจสอบหลายชนิดกับตัวแปรหนึ่งตัวเพื่อดูว่าเป็นฟังก์ชันสตริงหรืออะไรก็ตาม ในโครงการนี้ฉันต้องการประเภท สำหรับสิ่งนี้ฉันใช้อาเรย์ประเภทและตรวจสอบaccepted_types.indexOf(typeof value) !== -1เพื่อดูว่าอยู่ในประเภทหรือไม่ ในสถานการณ์เช่นนี้ข้อยกเว้นจะเป็นสิ่งต้องห้ามในความคิดของฉัน
Quentin Engles

2

ลองสิ่งนี้:

callback instanceof Function

1
ใช้งานไม่ได้ มันจะยังคงให้ข้อผิดพลาด คุณควรลองด้วยตัวเองก่อนโพสต์เป็นคำตอบ
vbullinger

@vbullinger ฉันเพิ่งทดสอบอีกครั้งใน Chrome, Firefox และ Safari - ใช้ได้ทุกที่ คุณใช้เครื่องยนต์ตัวไหนประสบปัญหา?
eWolf

Firefox คุณทดสอบกรณีที่ไม่มีการโทรกลับหรือไม่
vbullinger

นั่นเป็นเพราะคุณอ้างถึงตัวแปรที่ไม่ได้กำหนดโดยตรงซึ่งไม่สามารถใช้งานได้: pastebin.com/UQz2AmzH
eWolf

3
มันจะทำงานเมื่อใช้กับพารามิเตอร์ฟังก์ชั่นซึ่งเป็นสิ่งที่ผู้เขียนขอ - ฉันคิดว่า ECMAScript แยกกรณีของตัวแปรที่ไม่มีอยู่และตัวแปรที่มีอยู่กับค่าที่ไม่ได้กำหนด มันจะน่าสนใจที่จะรู้เพิ่มเติมเกี่ยวกับเรื่องนี้
eWolf

2

หากคุณดูที่แหล่งที่มาของห้องสมุด @Venkat Sudheer Reddy Aedama พูดถึงขีดล่างคุณสามารถเห็นสิ่งนี้:

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

นี่เป็นเพียงคำใบ้ของฉันคำใบ้คำตอบ:>




1

ฉันกำลังหาวิธีตรวจสอบว่ามีการกำหนดฟังก์ชั่น jQuery หรือไม่และไม่พบว่าง่าย

อาจจำเป็นต้องใช้;)

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

เช่นเดียวกับที่type0f($.datepicker) !== undefiledอื่นจะเป็นobject
vladkras

0

หากcallback()คุณกำลังโทรหาไม่ใช่เพียงครั้งเดียวในฟังก์ชั่นคุณสามารถเริ่มต้นอาร์กิวเมนต์เพื่อนำมาใช้ใหม่:

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

ตัวอย่างเช่น:

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

    alert(text);

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

ข้อ จำกัด คือมันจะดำเนินการโต้แย้งกลับแม้ว่ามันจะไม่ได้กำหนด


0

สำหรับฟังก์ชั่นทั่วโลกคุณสามารถใช้สิ่งนี้แทนevalคำแนะนำในหนึ่งในคำตอบ

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

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

คุณสามารถใช้global.f instanceof Functionเช่นกัน แต่ afaik ค่าของFunctionจะแตกต่างกันในเฟรมที่แตกต่างกันดังนั้นมันจะทำงานเฉพาะกับแอปพลิเคชันเฟรมเดียวอย่างถูกต้อง นั่นเป็นเหตุผลที่เรามักจะใช้typeofแทน โปรดทราบว่าในบางสภาพแวดล้อมอาจมีความผิดปกติtypeof fเช่นกันโดย MSIE 6-8 ฟังก์ชั่นบางอย่างเช่นalertมีประเภท "วัตถุ"

โดยฟังก์ชั่นท้องถิ่นคุณสามารถใช้หนึ่งในคำตอบที่ได้รับการยอมรับ คุณสามารถทดสอบว่าฟังก์ชั่นท้องถิ่นหรือทั่วโลกเช่นกัน

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

เพื่อตอบคำถามรหัสตัวอย่างทำงานให้ฉันโดยไม่มีข้อผิดพลาดในเบราว์เซอร์ล่าสุดดังนั้นฉันไม่แน่ใจว่าเกิดปัญหาอะไร:

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

หมายเหตุ: ฉันจะใช้callback !== undefinedแทนcallback != nullแต่พวกเขาเกือบจะเหมือนกัน


0

ส่วนใหญ่ถ้าไม่ใช่คำตอบก่อนหน้าทั้งหมดมีผลข้างเคียงที่จะเรียกใช้ฟังก์ชั่น

ปฏิบัติที่ดีที่สุดที่นี่

คุณมีฟังก์ชั่น

function myFunction() {
        var x=1;
    }
วิธีทดสอบโดยตรงสำหรับมัน

//direct way
        if( (typeof window.myFunction)=='function')
            alert('myFunction is function')
        else
            alert('myFunction is not defined');
ใช้สตริงเพื่อให้คุณมีที่เดียวเท่านั้นในการกำหนดชื่อฟังก์ชั่น

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


0

หากคุณต้องการกำหนดฟังก์ชั่นใหม่วิธีที่ดีที่สุดคือใช้ตัวแปรฟังก์ชั่นซึ่งกำหนดไว้ในลำดับการเกิดขึ้นเนื่องจากฟังก์ชั่นถูกกำหนดไว้ทั่วโลกไม่ว่าจะเกิดขึ้นที่ใด

ตัวอย่างของการสร้างฟังก์ชั่นใหม่ที่เรียกใช้ฟังก์ชั่นก่อนหน้านี้ที่มีชื่อเดียวกัน:

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


-2

โซลูชันบรรทัดเดียว:

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

ตัวอย่างของเขาแสดงให้เห็นว่าเขาต้องการให้เรียกใช้ฟังก์ชันหากมีการกำหนดและถ้าไม่เป็นเช่นนั้นจะไม่มีอะไรเกิดขึ้น jsfiddle.net/nh1cxxg6ฟังก์ชั่นที่คืนค่าเท็จ / เท็จยังคงถูกเรียก แน่นอนว่าสิ่งนี้จะไม่ทำงานเมื่อคุณต้องการส่งคืนค่า
กลั้ว Alajmovic

อ่าฉันอ่านคำถามผิด อย่างไรก็ตามสิ่งนี้จะทำให้เกิดข้อยกเว้นหากการโทรกลับไม่ใช่ฟังก์ชัน
Frank Bryce
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.