ผ่านฟังก์ชั่น JavaScript เป็นพารามิเตอร์


665

ฉันจะส่งผ่านฟังก์ชั่นเป็นพารามิเตอร์โดยไม่มีฟังก์ชั่นที่ดำเนินการในฟังก์ชั่น "ผู้ปกครอง" หรือใช้eval()? (ตั้งแต่ฉันอ่านว่ามันไม่ปลอดภัย)

ฉันมีสิ่งนี้:

addContact(entityId, refreshContactList());

ใช้งานได้ แต่ปัญหาคือrefreshContactListไฟไหม้เมื่อเรียกใช้ฟังก์ชันแทนที่จะใช้เมื่อใช้งานฟังก์ชัน

ฉันสามารถใช้มันได้eval()แต่ไม่ใช่วิธีปฏิบัติที่ดีที่สุดตามที่ฉันได้อ่าน ฉันจะส่งผ่านฟังก์ชันเป็นพารามิเตอร์ใน JavaScript ได้อย่างไร

คำตอบ:


930

คุณเพียงแค่ต้องลบวงเล็บ:

addContact(entityId, refreshContactList);

สิ่งนี้จะผ่านฟังก์ชันโดยไม่ต้องดำเนินการก่อน

นี่คือตัวอย่าง:

function addContact(id, refreshCallback) {
    refreshCallback();
    // You can also pass arguments if you need to
    // refreshCallback(id);
}

function refreshContactList() {
    alert('Hello World');
}

addContact(1, refreshContactList);

6
@stevefenton พิจารณาปรับปรุงคำตอบของคุณด้วยความคิดเห็น h2ooooooo มันจะมีประโยชน์มาก
มอร์แกนไวลด์

5
ตามคำถามโทรกลับไม่ยอมรับพารามิเตอร์ซึ่งเป็นสาเหตุที่ฉันได้ทิ้งพวกเขาออกจากตัวอย่าง ฉันจะเพิ่มความคิดเห็นเกี่ยวกับมัน
เฟนตัน

4
@Veverke มันจะมีลักษณะเช่นนี้ ...addContact(1, function(id) { console.log(id); });
Fenton

4
@Steve Fenton: หลังจากอ่านคำตอบของคุณฉันถามตัวเองว่าทำไมฉันถึงถาม ... :-)
Veverke

1
ไวยากรณ์การเรียนใน ECMAScript จะไม่ได้=เข้าสู่ระบบ ... มากกว่าclass myFuncs { class myFuncs = {คุณจะต้องทำงานในสภาพแวดล้อมที่สนับสนุนไวยากรณ์ของคลาส (เบราว์เซอร์บางตัวเท่านั้นที่รองรับ) หากคุณยังคงดิ้นรนมันอาจเหมาะกับคำถามใหม่ทั้งหมดเนื่องจากปัญหาของคุณไม่ได้เกี่ยวกับการส่งผ่านฟังก์ชั่น - เป็นไวยากรณ์ ES ทั่วไป
เฟนตัน

338

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

function foo(x) {
    alert(x);
}
function bar(func) {
    func("Hello World!");
}

//alerts "Hello World!"
bar(foo);

แต่บางครั้งคุณอาจต้องการส่งผ่านฟังก์ชั่นที่มีการรวมอาร์กิวเมนต์แต่ไม่มีการเรียกใช้จนกว่าจะมีการเรียกกลับ ในการทำสิ่งนี้เมื่อเรียกใช้ให้ใส่มันในฟังก์ชันที่ไม่ระบุตัวตนเช่นนี้

function foo(x) {
   alert(x);
}
function bar(func) {
   func();
}

//alerts "Hello World!" (from within bar AFTER being passed)
bar(function(){ foo("Hello World!") });

หากคุณต้องการคุณสามารถใช้ฟังก์ชั่นใช้และมีพารามิเตอร์ที่สามซึ่งเป็นอาร์เรย์ของอาร์กิวเมนต์เช่น:

function eat(food1, food2)
{
    alert("I like to eat " + food1 + " and " + food2 );
}
function myFunc(callback, args)
{
    //do stuff
    //...
    //execute callback when finished
    callback.apply(this, args);
}

//alerts "I like to eat pickles and peanut butter"
myFunc(eat, ["pickles", "peanut butter"]); 

71
สิ่งนี้ควรได้รับการจัดอันดับที่สูงขึ้นในขณะที่เขาพูดถึงวิธีส่งผ่านฟังก์ชั่นที่มีข้อโต้แย้ง
เดลตานีน

3
และสิ่งที่ฉันจะเพิ่มในส่วนนี้ก็คือคุณสมบัตินี้เพียงอย่างเดียว - ความสามารถในการส่งผ่านฟังก์ชัน JavaScript เป็นอาร์กิวเมนต์หรือตัวแปรหรือสิ่งที่คล้ายกัน - เป็นคุณลักษณะที่ทำให้ JavaScript มีประสิทธิภาพและยอดเยี่ยมในการเขียนโค้ด
TheHansinator

@ Compynerd255 ฉันเห็นด้วยกับสิ่งนี้และความสามารถในการสร้างตัวอักษรวัตถุได้อย่างรวดเร็วคือสองด้านที่ฉันโปรดปรานของ Javascript ฉันมักจะพลาดตัวอักษรวัตถุในภาษาที่ไม่มี
dallin

3
ฉันรู้สึกขอบคุณจาวาสคริปต์ที่มอบคุณสมบัตินี้และคุณ @dallin ให้ฉันรู้ว่ามันมีอยู่จริง
Dipendu Paul

สำหรับตัวอย่าง "ห่อไว้ในฟังก์ชันที่ไม่ระบุชื่อ" ในกรณีที่ไม่ชัดเจนฟังก์ชันที่ไม่ระบุชื่อจะส่งคืนฟังก์ชันนั้น (พร้อมพารามิเตอร์) และจะถูกเรียกใช้เมื่อถึงวงเล็บใน func () นี่ใช้เวลาซักพักนึงแล้วฉันจึงคิดว่ามันอาจช่วยคนอื่นได้
ฮับพิกเซล

51

ตัวอย่างที่ 1:

funct("z", function (x) { return x; });

function funct(a, foo){
    foo(a) // this will return a
}

ตัวอย่างที่ 2:

function foodemo(value){
    return 'hello '+value;
}

function funct(a, foo){
    alert(foo(a));
}

//call funct    
funct('world!',foodemo); //=> 'hello world!'

ดูนี่สิ


ในตัวอย่างแรกคุณควรเพิ่มคำหลัก return เช่นนี้ function function (a, foo) {return foo (a) // นี่จะคืน a} มิฉะนั้นคุณจะได้ undefined
Artem Fedotov

34

ในการผ่านฟังก์ชั่นเป็นพารามิเตอร์ให้ลบเครื่องหมายวงเล็บออก!

function ToBeCalled(){
  alert("I was called");
}

function iNeedParameter( paramFunc) {
   //it is a good idea to check if the parameter is actually not null
   //and that it is a function
   if (paramFunc && (typeof paramFunc == "function")) {
      paramFunc();   
   }
}

//this calls iNeedParameter and sends the other function to it
iNeedParameter(ToBeCalled); 

แนวคิดเบื้องหลังนี้คือฟังก์ชั่นค่อนข้างคล้ายกับตัวแปร แทนที่จะเขียน

function ToBeCalled() { /* something */ }

คุณอาจจะเขียนเช่นกัน

var ToBeCalledVariable = function () { /* something */ }

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

anotherFunction(ToBeCalledVariable);

2
เพียงtypeof paramFunc == "function"ก็เพียงพอสาเหตุถ้ามันไม่ได้ callable แล้วคุณสามารถละเลยมัน
Jimmy Knoot

16

มีวลีหนึ่งในโปรแกรมเมอร์ JavaScript: "Eval is Evil" ดังนั้นพยายามหลีกเลี่ยงค่าใช้จ่ายทั้งหมด!

นอกจากคำตอบของ Steve Fenton คุณสามารถส่งผ่านฟังก์ชั่นได้โดยตรง

function addContact(entity, refreshFn) {
    refreshFn();
}

function callAddContact() {
    addContact("entity", function() { DoThis(); });
}

8

ฉันตัดเส้นผมทั้งหมดออกด้วยปัญหานั้น ฉันไม่สามารถทำตัวอย่างด้านบนได้ดังนั้นฉันจึงชอบ:

function foo(blabla){
    var func = new Function(blabla);
    func();
}
// to call it, I just pass the js function I wanted as a string in the new one...
foo("alert('test')");

และมันก็ใช้งานได้อย่างมีเสน่ห์ ... สำหรับสิ่งที่ฉันต้องการอย่างน้อย หวังว่ามันจะช่วยได้บ้าง


6

ฉันแนะนำให้ใส่พารามิเตอร์ในอาเรย์แล้วแยกออกโดยใช้.apply()ฟังก์ชั่น ดังนั้นตอนนี้เราสามารถผ่านฟังก์ชั่นที่มีพารามิเตอร์จำนวนมากได้อย่างง่ายดายและดำเนินการในวิธีที่ง่าย

function addContact(parameters, refreshCallback) {
    refreshCallback.apply(this, parameters);
}

function refreshContactList(int, int, string) {
    alert(int + int);
    console.log(string);
}

addContact([1,2,"str"], refreshContactList); //parameters should be putted in an array

5

คุณยังสามารถใช้eval()เพื่อทำสิ่งเดียวกัน

//A function to call
function needToBeCalled(p1, p2)
{
    alert(p1+"="+p2);
}

//A function where needToBeCalled passed as an argument with necessary params
//Here params is comma separated string
function callAnotherFunction(aFunction, params)
{
    eval(aFunction + "("+params+")");
}

//A function Call
callAnotherFunction("needToBeCalled", "10,20");

แค่นั้นแหละ. ฉันกำลังมองหาโซลูชันนี้และลองวิธีแก้ปัญหาที่ให้ไว้ในคำตอบอื่น ๆ แต่ในที่สุดก็สามารถใช้งานได้จากตัวอย่างด้านบน


2

นี่เป็นอีกวิธีหนึ่ง:

function a(first,second)    
{        
return (second)(first);           
}     

a('Hello',function(e){alert(e+ ' world!');}); //=> Hello world     

2

ในความเป็นจริงดูเหมือนว่าซับซ้อนเล็กน้อยไม่ใช่

รับวิธีเป็นพารามิเตอร์:

 function JS_method(_callBack) { 

           _callBack("called");  

        }

คุณสามารถให้เป็นวิธีการพารามิเตอร์:

    JS_method(function (d) {
           //Finally this will work.
           alert(d)
    });

1
กรุณาอธิบายคำตอบของคุณ
MillaresRoo

2

คำตอบอื่น ๆ ทำหน้าที่ได้อย่างยอดเยี่ยมในการอธิบายสิ่งที่เกิดขึ้น แต่สิ่งสำคัญอย่างหนึ่ง "gotcha" คือการทำให้แน่ใจว่าสิ่งที่คุณผ่านคือการอ้างอิงถึงฟังก์ชั่น

ตัวอย่างเช่นหากคุณผ่านสตริงแทนฟังก์ชั่นคุณจะได้รับข้อผิดพลาด:

function function1(my_function_parameter){
    my_function_parameter();   
}

function function2(){
 alert('Hello world');   
}

function1(function2); //This will work

function1("function2"); //This breaks!

ดูJsFiddle


0

บางครั้งเมื่อคุณต้องการจัดการกับตัวจัดการเหตุการณ์ดังนั้นจึงจำเป็นต้องส่งผ่านเหตุการณ์เป็นอาร์กิวเมนต์ไลบรารีสมัยใหม่ส่วนใหญ่เช่นตอบสนองมุมอาจต้องการสิ่งนี้

ฉันต้องการแทนที่ฟังก์ชั่น OnSubmit (ฟังก์ชั่นจากห้องสมุดบุคคลที่สาม) ด้วยการตรวจสอบที่กำหนดเองบางส่วนบน reactjs และฉันผ่านฟังก์ชั่นและเหตุการณ์ทั้งสองด้านล่าง

เดิม

    <button className="img-submit" type="button"  onClick=
 {onSubmit}>Upload Image</button>

ทำฟังก์ชั่นใหม่uploadและเรียกว่าผ่านonSubmitและเหตุการณ์เป็นข้อโต้แย้ง

<button className="img-submit" type="button"  onClick={this.upload.bind(this,event,onSubmit)}>Upload Image</button>

upload(event,fn){
  //custom codes are done here
  fn(event);
}

-3

คุณสามารถใช้ JSON เพื่อจัดเก็บและส่งฟังก์ชัน JS

ตรวจสอบสิ่งต่อไปนี้:

var myJSON = 
{
    "myFunc1" : function (){
        alert("a");
    }, 
    "myFunc2" : function (functionParameter){
        functionParameter();
    }
}



function main(){
    myJSON.myFunc2(myJSON.myFunc1);
}

สิ่งนี้จะพิมพ์ 'a'

ต่อไปนี้มีผลเช่นเดียวกันกับด้านบน:

var myFunc1 = function (){
    alert('a');
}

var myFunc2 = function (functionParameter){
    functionParameter();
}

function main(){
    myFunc2(myFunc1);
}

ซึ่งก็มีผลเช่นเดียวกันกับต่อไปนี้:

function myFunc1(){
    alert('a');
}


function myFunc2 (functionParameter){
    functionParameter();
}

function main(){
    myFunc2(myFunc1);
}

และกระบวนทัศน์ของวัตถุที่ใช้ Class เป็นวัตถุต้นแบบ:

function Class(){
    this.myFunc1 =  function(msg){
        alert(msg);
    }

    this.myFunc2 = function(callBackParameter){
        callBackParameter('message');
    }
}


function main(){    
    var myClass = new Class();  
    myClass.myFunc2(myClass.myFunc1);
}

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