ทำความเข้าใจเกี่ยวกับฟังก์ชั่นการโทรกลับใน JavaScript ได้ดีขึ้น


163

ฉันเข้าใจว่าการส่งผ่านฟังก์ชันหนึ่งไปยังฟังก์ชันอื่นเป็นการโทรกลับและเรียกใช้งานได้ แต่ฉันไม่เข้าใจการนำไปใช้ที่ดีที่สุด ฉันกำลังมองหาตัวอย่างพื้นฐานอย่างนี้:

var myCallBackExample = {
    myFirstFunction : function( param1, param2, callback ) {
        // Do something with param1 and param2.
        if ( arguments.length == 3 ) {
            // Execute callback function.
            // What is the "best" way to do this?
        }
    },
    mySecondFunction : function() {
        myFirstFunction( false, true, function() {
            // When this anonymous function is called, execute it.
        });
    }
};

ใน myFirstFunction ถ้าฉันกลับโทรกลับใหม่ () แล้วมันจะทำงานและดำเนินการฟังก์ชั่นที่ไม่ระบุชื่อ แต่ดูเหมือนจะไม่เป็นวิธีที่ถูกต้องสำหรับฉัน


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

2
โดยการขัดแย้งทางที่มีอาร์เรย์เช่น แต่ไม่อาร์เรย์ดังนั้นคุณจึงไม่สามารถทำ argument.length แต่คุณสามารถแปลงเป็นอาร์เรย์โดยใช้วิธีการชิ้น ...
paul

1
@ พอลถึงแม้ว่าคุณจะถูกต้องว่าargumentsไม่ใช่อาร์เรย์คุณยังสามารถอ้างอิงความยาวของมันได้arguments.length- ลองทำดู คุณสมบัตินี้อ้างถึงจำนวนอาร์กิวเมนต์ที่ส่งผ่านจริงและไม่จำเป็นต้องเป็นจำนวนพารามิเตอร์ในลายเซ็นฟังก์ชัน
hotshot309

คำตอบ:


132

คุณสามารถพูดได้

callback();

อีกวิธีหนึ่งคุณสามารถใช้callวิธีการถ้าคุณต้องการปรับค่าthisภายในโทรกลับ

callback.call( newValueForThis);

ภายในฟังก์ชั่นthisจะเป็นสิ่งที่newValueForThisเป็น


91

คุณควรตรวจสอบว่ามีการติดต่อกลับหรือไม่และเป็นฟังก์ชันที่ปฏิบัติการได้:

if (callback && typeof(callback) === "function") {
    // execute the callback, passing parameters as necessary
    callback();
}

จำนวนมากของห้องสมุด (jQuery, โดโจ ฯลฯ ) ใช้รูปแบบคล้ายกันสำหรับการทำงานไม่ตรงกันของพวกเขาเช่นเดียวกับ Node.js สำหรับฟังก์ชั่น async ทั้งหมด (ปกติ nodejs ผ่านerrorและdataจะโทรกลับ) การดูรหัสต้นฉบับจะช่วยได้!


ทำไมคุณcallbackถึงโยนสตริงแล้วตรวจสอบประเภทของมัน? สิ่งนี้จะปรับปรุงประสิทธิภาพหรือไม่ นี่เหมือนกับการตรวจสอบประเภทการตรวจสอบว่าบูลีนที่แปลงกลับมาเป็นจริงจากนั้นตรวจสอบประเภทอีกครั้งและทดสอบกับสตริง ... คุณช่วยอธิบายได้ไหม
headacheCoder

ฉันอยากรู้ว่าทำไมคุณต้องมีการยืนยันครั้งแรกสำหรับการโทรกลับ ... เพื่อตรวจสอบโมฆะหรือไม่ได้กำหนด? จะไม่typeof(callback)ประสบความสำเร็จสำหรับคุณหรือไม่ typeof(null) === "Object",typeof("undefined") === "undefined"
PJH

1
ลัดวงจรและ. หากไม่มีการโทรกลับอย่ารบกวนการคำนวณประเภทของมัน แม้ว่าคุณพูดถูก ไม่จำเป็นต้องใช้กับ typeof () แต่ฉันจะทำ jsperf และดูว่าการลัดวงจรคุ้มค่าหรือไม่
arunjitsingh

@headacheCoder - callbackไม่ได้ถูกส่งไปยังสตริงประเภทของมันจะถูกตรวจสอบเพื่อดูว่ามันเป็นฟังก์ชั่นก่อนที่มันจะถูกเรียก รหัสคงจะยอมรับcallbackเป็นอาร์กิวเมนต์และมีความไม่แน่นอนว่าอาร์กิวเมนต์เป็นประเภท callable - หรือบางทีอาจจะขัดแย้งเป็นประเภทต่าง ๆ ในความพยายามที่จะให้รูปแบบของความแตกต่างที่รหัสอาจตอบสนองแตกต่างกันไปที่แตกต่างกันtypeofข้อโต้แย้ง
LeeGee

34

มี 3 ความเป็นไปได้หลักในการเรียกใช้ฟังก์ชัน:

var callback = function(x, y) {
    // "this" may be different depending how you call the function
    alert(this);
};
  1. โทรกลับ (argument_1, argument_2);
  2. callback.call (some_object, argument_1, argument_2);
  3. callback.apply (some_object, [argument_1, argument_2]);

วิธีที่คุณเลือกขึ้นอยู่กับว่า:

  1. คุณมีอาร์กิวเมนต์ที่เก็บไว้ใน Array หรือเป็นตัวแปรที่แตกต่างกัน
  2. คุณต้องการเรียกใช้ฟังก์ชันนั้นในบริบทของวัตถุบางอย่าง ในกรณีนี้การใช้คำสำคัญ "this" ในการโทรกลับนั้นจะอ้างอิงวัตถุที่ส่งผ่านเป็นอาร์กิวเมนต์ในการโทร () หรือใช้ () หากคุณไม่ต้องการผ่านบริบทวัตถุให้ใช้ null หรือไม่ได้กำหนด ในกรณีหลังวัตถุทั่วโลกจะถูกใช้สำหรับ "นี้"

เอกสารสำหรับFunction.call , Function.apply


6

การโทรกลับเป็นเรื่องเกี่ยวกับสัญญาณและ "ใหม่" เกี่ยวกับการสร้างอินสแตนซ์ของวัตถุ

ในกรณีนี้มันจะเหมาะสมกว่าที่จะดำเนินการเพียงแค่ "โทรกลับ ();" กว่า "return new callback ()" เพราะคุณไม่ได้ทำสิ่งใดที่มีค่าส่งคืนอยู่ดี

(และ arguments.length == 3 การทดสอบเป็น clunky, fwiw ดีกว่าที่จะตรวจสอบว่ามีการเรียกกลับพารามิเตอร์และมีฟังก์ชั่น)


6

การดำเนินการที่เหมาะสมจะเป็น:

if( callback ) callback();

สิ่งนี้ทำให้พารามิเตอร์ callback เป็นทางเลือก ..


เกิดอะไรขึ้นถ้าอาร์กิวเมนต์โทรกลับไม่ได้เป็นฟังก์ชั่น?
Yaki Klein

2

คุณสามารถใช้ได้:

if (callback && typeof(callback) === "function") {
    callback();
}

ตัวอย่างด้านล่างมีความครอบคลุมมากกว่าเล็กน้อย:

function mySandwich(param1, param2, callback) {
  alert('Started eating my sandwich.\n\nIt has: ' + param1 + ', ' + param2);
  var sandwich = {
      toppings: [param1, param2]
    },
    madeCorrectly = (typeof(param1) === "string" && typeof(param2) === "string") ? true : false;
  if (callback && typeof(callback) === "function") {
    callback.apply(sandwich, [madeCorrectly]);
  }
}

mySandwich('ham', 'cheese', function(correct) {
  if (correct) {
    alert("Finished eating my " + this.toppings[0] + " and " + this.toppings[1] + " sandwich.");
  } else {
    alert("Gross!  Why would I eat a " + this.toppings[0] + " and " + this.toppings[1] + " sandwich?");
  }
});


1

นี่คือตัวอย่างพื้นฐานที่อธิบายcallback()ฟังก์ชันใน JavaScript:

var x = 0;

function testCallBack(param1, param2, callback) {
  alert('param1= ' + param1 + ', param2= ' + param2 + ' X=' + x);
  if (callback && typeof(callback) === "function") {
    x += 1;
    alert("Calla Back x= " + x);
    x += 1;
    callback();
  }
}

testCallBack('ham', 'cheese', function() {
  alert("Function X= " + x);
});

JSFiddle


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