Передача функции с параметрами в качестве параметра?

151

Можно ли передать функцию javascript с параметрами в качестве параметра?

Пример:

$(edit_link).click( changeViewMode( myvar ) );
Lucia
источник
5
Похоже, JQuery, и, скорее всего, так, но это не имеет значения. Использование или параметры и функции одинаковы независимо от того, какие библиотеки Javascript вы используете.
Гуффа
@Guffa - мне было интересно, стоит ли отмечать его jQuery
Russ Cam
1
@Lucia Пожалуйста, подумайте об изменении принятого ответа на это .
Михал Перлаковский
Если вы работаете с React, подумайте над stackoverflow.com/questions/41369497/…
Майкл Фрейдгейм

Ответы:

244

Используйте «закрытие»:

$(edit_link).click(function(){ return changeViewMode(myvar); });

Это создает анонимную временную оболочку функции, которая знает о параметре и передает его фактической реализации обратного вызова.

Фердинанд Бейер
источник
3
Если вы хотите вызвать функцию объекта, вам нужно вызвать bind (). myObj.click (function () {this.doSomething ();} .bind (myObj)); Это сделает «это» myObj.
Эли
1
Разве это не проблема с производительностью при работе со многими из них? Например, вы рендеринг onPress в ряд, и у вас есть 10000 строк. Это создает новую временную оболочку анонимной функции для каждой строки. Есть ли другой способ сделать это?
Джошуа Пинтер
@JoshuaPinter Сама техника не проблема. Если вам требуется один и тот же вызов функции 10000 раз, вы можете просто сохранить оболочку в переменной, чтобы создать ее только один раз. Если вам нужно пройти 10 000 различных контекстов, вы мало что можете сделать. Остерегайтесь преждевременной оптимизации: как всегда, с производительностью, вы должны измерить, чтобы увидеть, есть ли проблема или нет. Современные механизмы JavaScript очень мощные и могут оптимизировать код неожиданными способами.
Фердинанд Бейер
@FerdinandBeyer Отлично, спасибо за совет. Друг сказал мне, что это плохая практика, и что вы должны вместо этого использовать this.myFunction = this.myFunction.bind(this)в своем constructorметоде. Но, как вы сказали, когда вам нужно передать разные контексты для каждого из них, например, для всех разных строк, по которым вы щелкаете, чтобы открыть страницу с подробностями этой строки, это невозможно избежать.
Джошуа Пинтер
@FerdinandBeyer, допустим, что myvar является строкой, и она изменяется между двумя последовательными вызовами передачи changeViewMode как замыкания, но changeViewMode всегда получает первое значение myvar, я хочу вызвать функцию замыкания с другим значением аргумента, назначенным для той же переменной myvar,
nmxprime
42

Использование Function.prototype.bind(). Цитируя MDN:

bind()Метод создает новую функцию , которая при вызове, имеет свой thisнабор ключевых предоставленному значения с заданной последовательности аргументов , предшествующих любой при условии , когда новая функция вызывается.

Он поддерживается всеми основными браузерами, включая IE9 +.

Ваш код должен выглядеть так:

$(edit_link).click(changeViewMode.bind(null, myvar));

Примечание: я предполагаю, что вы находитесь в глобальном контексте, т.е. thisпеременная есть window; в противном случае используйте thisвместо null.

Михал Перлаковский
источник
Спасибо, это помогло мне. Использовал это так:$.ajax(url).done(handler.bind(this, var1, var2));
Томас
2
Какой вариант лучше? Использование замыкания или использование функции связывания? Пожалуйста, дайте мне знать, если это повлияет на производительность
Varun
5
@Varun Смотрите, почему связывание медленнее, чем закрытие?
Михал Перлаковский
15

Нет, но вы можете передать один без параметров, и сделать это:

$(edit_link).click(
  function() { changeViewMode(myvar); }
);

Таким образом, вы передаете анонимную функцию без параметров, которая затем вызывает вашу параметризованную функцию с переменной в закрытии

Клайд
источник
8

Да, вот так:

$(edit_link).click(function() { changeViewMode(myvar) });
Филипп Лейбер
источник
7

Или, если вы используете es6, вы должны быть в состоянии использовать функцию стрелки

$(edit_link).click(() => changeViewMode(myvar));
Кристиан Бартрам
источник
2

Ты можешь сделать это

var message  = 'Hello World';

var callback = function(){
alert(this)
}.bind(message);

а потом

function activate(callback){
  callback && callback();
}

activate(callback);

Или, если ваш обратный вызов содержит более гибкую логику, вы можете передать объект.

демонстрация

Александр Саргсян
источник
2

Вот пример, следующий за подходом Фердинанда Бейера:

function function1()
{
    function2(function () { function3("parameter value"); });
}
function function2(functionToBindOnClick)
{
    $(".myButton").click(functionToBindOnClick);
}
function function3(message) { alert(message); }

В этом примере «значение параметра» передается от function1 к function3 через function2 с помощью переноса функции.

erionpc
источник