Используя Function.prototype.bind с массивом аргументов?
13693 просмотра
10 ответа
Как я могу вызвать Function.prototype.bind с массивом аргументов, в отличие от жестко закодированных аргументов? (Не использует ECMA6, поэтому нет оператора спреда).
Я пытаюсь поместить оболочку обещаний вокруг модуля, который использует обратные вызовы, и я хочу связать все аргументы, переданные моему методу оболочки, и связать их. Затем я хочу вызвать частично примененную связанную функцию с моим собственным обратным вызовом, который разрешит или отклонит обещание.
var find = function() {
var deferred, bound;
deferred = Q.defer();
bound = db.find.bind(null, arguments);
bound(function(err, docs) {
if(err) {
deferred.fail(err);
} else {
deferred.resolve(docs);
}
});
return deferred.promise;
}
Но очевидно, что это не работает, потому что bind ожидает аргументы, а не массив аргументов. Я знаю, что мог бы сделать это, вставив мой обратный вызов в конец массива arguments и используя apply:
arguments[arguments.length] = function(err, docs) { ... }
db.find.apply(null, arguments);
Или путем перебора массива arguments и повторного связывания функции для каждого аргумента:
var bound, context;
for(var i = 0; i < arguments.length; i++) {
context = bound ? bound : db.find;
bound = context.bind(null, arguments[i]);
}
bound(function(err, docs) { ... })
Но оба эти метода чувствуют себя грязными. Есть идеи?
Автор: Dan Prince Источник Размещён: 12.11.2019 09:50Ответы (10)
78 плюса
.bind
это нормальная функция, так что вы можете вызвать .apply
ее.
Все, что вам нужно сделать, это передать исходную функцию в качестве первого параметра и желаемую THIS
переменную в качестве первого элемента в массиве аргументов:
bound = db.find.bind.apply(db.find, [null].concat(arguments));
// ^-----^ ^-----^ THIS
Будет ли это считаться чище или нет, остается за читателем.
Автор: Felix Kling Размещён: 02.02.2014 05:3911 плюса
Ниже приведен общий фрагмент кода, который я использую во всех своих проектах:
var bind = Function.bind;
var call = Function.call;
var bindable = bind.bind(bind);
var callable = bindable(call);
Теперь bindable
функцию можно использовать для передачи массива bind
следующим образом:
var bound = bindable(db.find, db).apply(null, arguments);
На самом деле вы можете кэшировать bindable(db.find, db)
для ускорения привязки следующим образом:
var findable = bindable(db.find, db);
var bound = findable.apply(null, arguments);
Вы можете использовать findable
функцию с массивом аргументов или без него:
var bound = findable(1, 2, 3);
Надеюсь это поможет.
Автор: Aadit M Shah Размещён: 15.02.2014 03:139 плюса
Ответ Феликса не сработал для меня, потому что arguments
объект на самом деле не является массивом (как отметил Оттс). Решением для меня было просто переключиться bind
и apply
:
bound = db.find.apply.bind(db.find, null, arguments);
Автор: Joel
Размещён: 06.06.2014 04:50
4 плюса
Для тех, кто использует ES6, Babel компилирует:
db.find.bind(this, ...arguments)
чтобы:
db.find.bind.apply(db.find, [this].concat(Array.prototype.slice.call(arguments)));
Я думаю, будет справедливо сказать, что Бабель довольно определенна. Кредит @ lorenz-lo-sauer, хотя, это почти идентично.
Автор: nathancahill Размещён: 30.04.2017 05:481 плюс
Почему бы просто не выполнить привязку к массиву arguments в соответствии с вашим примером и заставить bound()
функцию обрабатывать его так же, как массив ?
Судя по тому, как вы используете, вы передаете функцию в качестве последнего аргумента bound()
, то есть, передавая массив фактических аргументов, вы избегаете необходимости отделять аргументы от обратных вызовов внутри bound()
, что потенциально облегчает игру.
1 плюс
Обычно этой схемы достаточно:
//obj = db
//fnName = 'find'
var args = [this||null].concat(Array.prototype.slice.apply(arguments);
obj[fnName].bind.apply(obj[fnName], args);
Автор: Lorenz Lo Sauer
Размещён: 05.02.2015 12:17
1 плюс
Я нахожу следующее чище, чем принятые ответы
Function.bind.apply(db.find, [null].concat(arguments));
Автор: brillout
Размещён: 17.11.2016 12:19
1 плюс
Если кто-то ищет абстрактный образец:
var binded = hello.apply.bind(hello,null,['hello','world']);
binded();
function hello(a,b){
console.log(this); //null
console.log(a); //hello
console.log(b); //world
}
Автор: Paweł
Размещён: 14.08.2017 09:27
0 плюса
Просто была альтернативная идея, частично применить null
значение для контекста, а затем использовать apply
для вызова частично примененной функции.
bound = db.find.bind.bind(null).apply(null, arguments);
Это устраняет необходимость в слегка пугающем взгляде [null].concat()
на ответ @ Феликса.
0 плюса
Окончательный и простой ответ может быть
Function.apply.bind(this.method, this, arguments);
Вроде «трудно» понять, но аккуратно.
Автор: 131 Размещён: 25.11.2016 09:25Вопросы из категории :
- javascript Как определить, какой из указанных шрифтов был использован на веб-странице?
- javascript Валидация клиентской стороны ASP.Net
- javascript Длина объекта JavaScript
- javascript Получение текста из выпадающего списка
- javascript Скрипт входа со скрытыми кнопками
- functional-programming Удаление элементов с помощью Array.map в JavaScript
- functional-programming В чем разница между процедурным программированием и функциональным программированием?
- functional-programming Что такое хвостовая рекурсия?
- functional-programming Что такое «Currying»?
- functional-programming Почему функциональные языки?
- promise jQuery откладывает и обещает - .then () против .done ()
- promise Каковы различия между отложенным, обещанием и будущим в JavaScript?
- promise Что такое std :: prom?
- promise How to include multiple js files using jQuery $.getScript() method
- promise Angular JS: как связать с обещаниями
- partial-application В чем разница между каррированием и частичным применением?
- partial-application Связующие аргументы Python
- partial-application Полезность (как в практических приложениях) Curry против частичного применения в Scala
- partial-application Replace parameter in lambda expression
- partial-application Можно ли частично применить второй аргумент функции, которая не принимает аргументов с ключевыми словами?