2017-02-14 3 views
1

Здесь находятся две функции обратного вызова:Как передать функцию обратного вызова с несколькими возможными списками параметров

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

function callback_b(p){ 
    alert('b says'+ p)' 
} 

Если я хочу использовать callback_a

function test(callback){ 
    if(condition){ 
    callback(); 
    } 
} 

test(callback_a); 

Но функция test не применима к callback_b, Итак, как реализовать общую функцию, с которой вы можете передавать некоторые функции обратных вызовов с несколькими списками параметров.

+0

Почему бы» t просто вызовите тест следующим образом: 'test (callback_b ('what b должен сказать'))' – malarres

+1

@malarres Он по-прежнему будет выполните 'callback_b', если условие equls false – qslcna

+0

@malarres: ** И ** он выполнит' callback_b' * first *, перед 'test'. –

ответ

2

Существует специальный объект, называемый arguments, который создается при вызове функции. Это массив-подобный объект, который представляет аргументов, передаваемых в функцию:

Он может быть использован, как это:

test(); 
    // no arguments passed, but it still gets created: 
    // arguments.length = 0 
    // arguments >> [] 

test(a); 
    // ONE argument passed: 
    // arguments.length = 1 
    // arguments >> [a] 

test(a,b,c,d); 
    // FOUR arguments passed: 
    // arguments.length = 4 
    // arguments >> [a,b,c,d] 

Зная это, можно вызвать функцию обратного вызова с остальными аргументами, переданными в от родительской функции, используя apply так:

function test(callback) { 
    callback.apply(null, Array.prototype.slice.call(arguments, 1)); 
} 
// arguments passed into test are available in the function scope when 
// .slice is used here to only pass the portion of the arguments 
// array relevant to the callback (i.e. any arguments minus the 
// first argument which is the callback itself.) 
// 
// N.B. The arguments object isn't an array but an array like object so 
// .slice isn't available on it directly, hence .call was used here) 

Может быть стоит читать на:

+0

Это не похоже на какое-либо отношение к вопросу. Вопрос заключается в передаче различных функций в' test', которые имеют разные формальные списки параметров. Ответ на вопрос о количестве аргументов, переданных 'test'.Как это даже начинает отвечать на вопрос? Отдельно, пример в конце передает' callback' самому себе, что кажется странным делом, особенно учитывая, что 'callback_b' делает с его параметром. –

+0

@ TJCrowder: OP posted: _ «Как реализовать общую функцию, с помощью которой вы можете передавать некоторые функции обратного вызова с несколькими возможными списками параметров "_. Я читал, как они обращаются с различными обратными вызовами, список аргументов которых варьируется и до сих пор могут передавать соответствующие аргументы через обратные вызовы. – Pineda

+0

@ T.J.Кроудер: согласился с тем, что мой пример странный, вначале я включил предостережение о том, что первым аргументом будет обратный вызов, но я думал, что это будет подразумеваться, если ОП поймет аргументы за моим ответом (и, следовательно, обработайте аргументы в 'test' или 'callback' – Pineda

0

Вы можете передать параметр при вызове функции обратного вызова

function test(callback){ 
 
    if(condition){ 
 
    callback(); 
 
    } 
 
    else if(other condition){ 
 
    callback("b"); 
 
    } 
 
} 
 

 
test(callback_b);

Вы можете написать функцию обратного вызова, как

function callback_a_b(){ 
 
    if(arguments.length){ 
 
    var arg = [].slice.call(arguments); 
 
    alert('b says'+ arg[0]) 
 
    } 
 
    else{ 
 
    alert('a'); 
 
    } 
 
    
 
}

+0

Я хочу использовать функцию 'test' таким образом, вы можете передавать' callback_a' и 'callback_b' на нее, и она должна работать :) – qslcna

+0

Но это не сработает, если вы передаете callback_a как функция обратного вызова. Это именно та проблема, с которой OP хочет получить ответ. – Connum

+0

@qslcna см. Обновленный ответ – ricky

0

Вы можете передать анонимную функцию в качестве обратного вызова, который сам вернет вашу функцию обратного вызова с параметрами.

test(function() { return callback_b(' how are you'); }); 

посмотреть рабочий фрагмент кода, который будет первым использовать callback_a, затем callback_b (с параметром) в качестве обратного вызова:

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

 
function callback_b(p){ 
 
    alert('b says'+ p); 
 
} 
 

 
function test(callback){ 
 
    if(true){ 
 
    callback(); 
 
    } 
 
} 
 

 
test(callback_a); 
 
test(function() { return callback_b(' how are you'); });

2

Так как реализовать общую функцию, которая вы можете передать некоторую функцию обратных вызовов с несколькими возможными списками параметров.

В принципе, вы этого не сделаете. Функция, получающая обратный вызов, отвечает за то, что обратный вызов получает в качестве аргументов. Когда вы вызываете Array#forEach, это Array#forEach, который решает, какие аргументы получает ваш обратный вызов. Аналогично, String#replace определяет, с каким вызовом будет обращаться.

Ваша задача - сказать, что сделает test, как он будет называть его обратный вызов. Тогда это работа человека, использующего test, чтобы написать обратный вызов соответствующим образом. Например: вы можете документировать test как вызов обратного вызова без аргументов. Если вызывающий абонент хочет использовать callback_b, то это зависит от того, что callback_b ожидает параметр. Есть несколько способов, они могут сделать это:

может обернуть его в другой функции:

test(function() { 
    callback_b("appropriate value here"); 
}); 

... или использовать Function#bind

test(callback_b.bind(null, "appropriate value here")); 

... но это их проблема , не ваш.

Замечание: Если они передадут вам callback_b, и вы вызываете его без каких-либо аргументов, вы не получите ошибку. JavaScript позволяет вам вызывать функцию с меньшим количеством аргументов, чем она ожидает, или больше. Как работает функция, которая зависит от автора функции.

+0

Я не уверен, подходит ли это для него _callback_. На самом деле, я просто хочу судить через 'test' перед выполнением' callback_a' или 'callback_b', чтобы определить, должны ли они выполняться. – qslcna

+0

@qslcna: Боюсь, я не понимаю ваш первый пункт выше. Вы передаете 'test' функцию и вызываете ее; это обратный вызов текстовой книги. Повторите свой второй пункт, вы можете проверить арность получаемой функции, посмотрев ее свойство 'length'. Это говорит о том, сколько формальных параметров, о которых он говорит, принимает, так что, например, 'function foo (a, b) {}' имеет 'foo.length'' 2'. (Но это сложно, параметры останова ES2015 и параметры по умолчанию не отображаются в арности функции.) –

+0

Первое, что я имею в виду, я не знаю, можно ли сказать, что это своего рода функция _callback_ – qslcna

0

Вы можете передать массив параметров, как вторые пары из test функции или в ES6 использовании распространения операта ator read more here

function test(callback, params){ 
    if(condition){ 
    if (params === undefined){ 
     callback(); 
    } else { 
     callback.apply(null, params); //params must be array 
     //ES6: callback(...params); 
    } 
    } 
} 

test(callback_a); 
test(callback_b, [" whatever"]); 
0

Я только что зарегистрировался в своем браузере (ffox 51.0.1), что следующие работы:

function test(callback,other_args){if(condition){callback(other_args);}} 

Результаты:

  • состояние = истинные
  • тест (callback_a)
    • => показывает предупреждение с 'а'
  • состояние = ложное
  • тест (callback_a)
    • => не показывает что-нибудь
  • условие = истина
  • тест (callback_b, "Pepe")
    • => показывает предупреждение с «Ъ sayspepe»
  • условие = ложь
  • тест (callback_b, "Pepe")
    • => не показывает что-нибудь
2

Есть три варианта:

  • Самый простой способ заключается в использовании спреда оператора:

    function test(callback, ...callback_args) { 
        callback(...callback_args); 
    } 
    

    в в этом случае вызов test для функции callback_b будет выглядеть так:

    test(callback_b,"b") 
    
  • Второй способ заключается в использовании arguments которые контекстные к любой функции в JavaScript:

    function test(callback) { 
        callback.apply(null, arguments.slice(1)); 
    } 
    

    призывание test для функции callback_b будет таким же:

    test(callback_b,"b") 
    
  • Другим вариантом является использование карриных функций.В этом случае вы должны определить b_callback как это (ES6 синтаксис):

    let callback_b = (p) =>() => void{ 
        alert('b says'+ p)' 
    } 
    

    или без ES6:

    function callback_b(p) { 
        return function(){ 
         alert('b says'+ p)' 
        } 
    } 
    

    и вызывать его так:

    test(callback_b("b")) 
    
Смежные вопросы