Передайте функцію 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); });
Фентон

4
@Steve Fenton: прочитавши вашу відповідь, я запитав себе, чому я запитав ... :-)
Veverke

1
Синтаксис класу в ECMAScript не матиме =ознаки ... class myFuncs {а не class myFuncs = {. Вам також потрібно буде працювати в середовищі, яке підтримувало синтаксис класу (ще не всі браузери його підтримують). Якщо ви все ще боретеся, це може бути краще підходити до зовсім нового питання, оскільки ваша проблема не стосується передачі функцій - це загальний синтаксис ES.
Фентон

337

Якщо ви хочете передати функцію, просто посилайтеся на неї по імені без дужок:

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

70
це слід класифікувати вище, оскільки він також вирішує, як передавати функцію з аргументами
дельтанін

3
І щось до цього я додам, це те, що лише ця функція - здатність передавати функції JavaScript у вигляді аргументів чи змінних тощо - є тією функцією, яка робить JavaScript настільки потужним та таким чудовим для кодування.
TheHansinator

@ Compynerd255 Я згоден, це і можливість швидкого створення об'єктних літералів - це два моїх улюблених аспекту Javascript. Мені завжди не вистачає об'єктних літералів мовами, які їх не мають.
Даллін

3
Я настільки вдячний Javascript за надану цю функцію, а ви @dallin за те, що ви повідомили, що вона існує.
Dipendu Пол

Для прикладу "загортання його в анонімну функцію", якщо це не очевидно, анонімна функція повертає саму функцію (з параметрами) і її викликають, коли вона дістається до дужок у func (). Це знадобило мені час, щоб зрозуміти, тому я подумав, що це може допомогти іншим.
hubpixel

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, як-от: функція funct (a, foo) {return foo (a) // це поверне a} в іншому випадку ви отримаєте невизначений
Артем Федотов

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"достатньо, тому що якщо вона не дзвонить, то ви можете її проігнорувати.
Джиммі Кнут

16

Серед програмістів JavaScript є фраза: "Eval is Evil", тому намагайтеся уникати цього будь-якою ціною!

Окрім відповіді Стіва Фентона, ви також можете передавати функції безпосередньо.

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

Інші відповіді - це прекрасна робота, описуючи те, що відбувається, але одна важлива «готча» - це переконатися, що все, що ви проходите, справді є посиланням на функцію.

Наприклад, якщо ви перейдете через рядок замість функції, ви отримаєте помилку:

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.
Меттью Лейтон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.