использовать функции.прототип.связывание с массивом аргументов?
Как я могу вызвать функцию.прототип.связывание с массивом аргументов, в отличие от жестко закодированных аргументов? (Не использует 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 ожидает аргументы, а не массив аргументов. Я знаю, что могу сделать это, вставив свой обратный вызов в конец массива аргументов и используя apply:
arguments[arguments.length] = function(err, docs) { ... }
db.find.apply(null, 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) { ... })
Но оба эти метода кажутся грязными. Есть идеи?10 ответов:
.bind
это нормальная функция, поэтому вы можете вызвать.apply
на нем.
Все, что вам нужно сделать, это передать исходную функцию в качестве первого парама и требуемую переменнуюTHIS
в качестве первого элемента в массиве аргументов:Можно ли считать это более чистым или нет, остается за читателем.bound = db.find.bind.apply(db.find, [null].concat(arguments)); // ^-----^ ^-----^ THIS
Ниже приведен общий фрагмент кода, который я использую во всех своих проектах:
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);
Надеюсь, это поможет.
Ответ Феликса не сработал для меня, потому что объект
arguments
на самом деле не является массивом (как указывал ОТТС). Решением для меня было просто переключитьbind
иapply
:bound = db.find.apply.bind(db.find, null, arguments);
Для тех, кто использует ES6, Babel компилирует:
db.find.bind(this, ...arguments)
Кому:
Я думаю, будет справедливо сказать, что Вавилон довольно категоричен. Хотя, надо отдать должное @lorenz-lo-sauer, он почти идентичен.db.find.bind.apply(db.find, [this].concat(Array.prototype.slice.call(arguments)));
Почему бы просто не привязать к массиву аргументов, как в вашем примере, и заставить функцию
bound()
обращаться с ним точно так же, как с массивом?Судя по тому, как вы используете функцию, вы затем передаете ее в качестве конечного аргумента в
bound()
, что означает, что, передавая фактический массив аргументов, вы избегаете необходимости отделять аргументы от обратных вызовов внутриbound()
, что потенциально облегчает игру.
В общем случае этой схемы достаточно:
//obj = db //fnName = 'find' var args = [this||null].concat(Array.prototype.slice.apply(arguments); obj[fnName].bind.apply(obj[fnName], args);
Я нахожу следующие более чистые, чем принятые ответы
Function.bind.apply(db.find, [null].concat(arguments));
Если кто-то ищет абстрактный образец:
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 }