ハードコーディングされた引数ではなく、引数の配列を使用してFunction.prototype.bindを呼び出すにはどうすればよいですか? (ECMA6を使用していないため、スプレッド演算子はありません)。
コールバックを使用するモジュールの周りにpromisesラッパーを配置しようとしています。ラッパーメソッドに渡されたすべての引数をバインドし、それらをバインドします。次に、部分的に適用されたバインドされた関数を自分のコールバックで呼び出します。これにより、約束が解決または拒否されます。
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;
}
しかし、バインドは引数の配列ではなく引数を要求するため、明らかにこれは機能しません。引数配列の最後にコールバックを挿入し、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) { ... })
しかし、これらの方法はどちらも汚い感じがします。何か案は?
.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
オブジェクトは実際には配列ではないため、Felixの答えはうまくいきませんでした(Ottsが指摘したように)。私にとっての解決策は、単にbind
とapply
を切り替えることでした:
bound = db.find.apply.bind(db.find, null, arguments);
ES6を使用している場合、Babelは次をコンパイルします。
db.find.bind(this, ...arguments)
に:
db.find.bind.apply(db.find, [this].concat(Array.prototype.slice.call(arguments)));
バベルはかなり決定的だと言ってもいいと思います。しかし、@ lorenz-lo-sauerに感謝します。ほとんど同じです。
あなたの例のように単純に引数配列にバインドし、bound()
関数にそれを配列としてのように処理させるのはなぜですか?
使用方法の見た目では、bound()
の最後の引数として関数を渡します。つまり、実際の引数配列を渡すことで、bound()
、プレイしやすくする可能性があります。
受け入れられた答えよりも次のことがわかりました
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
}
一般的に、このスキーマで十分です。
//obj = db
//fnName = 'find'
var args = [this||null].concat(Array.prototype.slice.apply(arguments);
obj[fnName].bind.apply(obj[fnName], args);
別のアイデアがあり、コンテキストにnull
値を部分的に適用し、apply
を使用して部分的に適用された関数を呼び出します。
_bound = db.find.bind.bind(null).apply(null, arguments);
_
これにより、@ Felixの回答で少し不気味に見える[null].concat()
の必要がなくなります。
決定的な簡単な答えは
Function.apply.bind(this.method, this, arguments);
ちょっと「難しい」とはいえ、きちんとしている。