124

Javascriptでは、パラメータをバインドせずに引数を関数にバインドするにはどうすればよいthisですか?

例えば:

//Example function.
var c = function(a, b, c, callback) {};

//Bind values 1, 2, and 3 to a, b, and c, leave callback unbound.
var b = c.bind(null, 1, 2, 3); //How can I do this without binding scope?

this関数のスコープ (設定= null など) もバインドする必要があるという副作用を回避するにはどうすればよいですか?

編集:

混乱させて申し訳ありません。引数をバインドし、後でバインドされた関数を呼び出して、元の関数を呼び出してバインドされた引数を渡した場合とまったく同じように動作させたい:

var x = 'outside object';

var obj = {
  x: 'inside object',
  c: function(a, b, c, callback) {
    console.log(this.x);
  }
};

var b = obj.c.bind(null, 1, 2, 3);

//These should both have exact same output.
obj.c(1, 2, 3, function(){});
b(function(){});

//The following works, but I was hoping there was a better way:
var b = obj.c.bind(obj, 1, 2, 3); //Anyway to make it work without typing obj twice?

私はまだこれに慣れていないので、混乱させてすみません。

ありがとう!

4

16 に答える 16

33

これを行うことはできますが、「これ」の値を設定するために使用される用語であるため、それを「バインディング」と考えないようにすることをお勧めします。おそらく、引数を関数に「ラップする」と考えてください。

あなたがすることは、クロージャーを介してそれに組み込まれた目的の引数を持つ関数を作成することです:

var withWrappedArguments = function(arg1, arg2)
    {
        return function() { ... do your stuff with arg1 and arg2 ... };
    }(actualArg1Value, actualArg2Value);

そこに構文があることを願っています。それが行うことは、いつでもどこでも呼び出すことができ、常にactualArg1ValueとactualArg2Value、およびその他に入れたいもので動作する withWrappedArguments() と呼ばれる関数を作成することです(変数に割り当てられた匿名関数です)。そこの。必要に応じて、呼び出し時にさらに引数を受け入れるようにすることもできます。その秘密は、最後の右中括弧の後の括弧です。これらにより、渡された値を使用して外側の関数がすぐに実行され、後で呼び出すことができる内側の関数が生成されます。渡された値は、関数が生成された時点で凍結されます。

これは事実上 bind が行うことですが、この方法では、ラップされた引数が単にローカル変数のクロージャであることが明示されており、この動作を変更する必要はありません。

于 2013-09-07T16:42:31.460 に答える
25

ES6 では、レスト パラメーターとスプレッド オペレーターを組み合わせて使用​​することで、これを簡単に行うことができます。

したがって、引数のみがバインドされ、コンテキスト ( ) がバインドされないことを除いて、bindArgsのように機能する関数を定義できます。bindthis

Function.prototype.bindArgs =
    function (...boundArgs)
    {
        const targetFunction = this;
        return function (...args) { return targetFunction.call(this, ...boundArgs, ...args); };
    };

次に、指定された関数fooとオブジェクトobjに対して、ステートメント

return foo.call(obj, 1, 2, 3, 4);

と同等です

let bar = foo.bindArgs(1, 2);
return bar.call(obj, 3, 4);

ここで、最初と 2 番目の引数のみが にバインドされますが、呼び出しで指定されbarたコンテキストobjが使用され、バインドされた引数の後に追加の引数が追加されます。戻り値は単純に転送されます。

于 2013-05-06T14:12:43.140 に答える
17

ネイティブbindメソッドthisでは、結果関数の値が失われます。ただし、コンテキストに引数を使用しないように共通のシムを簡単に再コーディングできます。

Function.prototype.arg = function() {
    if (typeof this !== "function")
        throw new TypeError("Function.prototype.arg needs to be called on a function");
    var slice = Array.prototype.slice,
        args = slice.call(arguments), 
        fn = this, 
        partial = function() {
            return fn.apply(this, args.concat(slice.call(arguments)));
//                          ^^^^
        };
    partial.prototype = Object.create(this.prototype);
    return partial;
};
于 2012-12-13T01:01:27.893 に答える
7

楽しみのためのもう 1 つの小さな実装:

function bindWithoutThis(cb) {
    var bindArgs = Array.prototype.slice.call(arguments, 1);

    return function () {
        var internalArgs = Array.prototype.slice.call(arguments, 0);
        var args = Array.prototype.concat(bindArgs, internalArgs);
        return cb.apply(this, args);
    };
}

使い方:

function onWriteEnd(evt) {}
var myPersonalWriteEnd = bindWithoutThis(onWriteEnd, "some", "data");
于 2014-02-08T11:42:20.607 に答える
2

例は恣意的なものであるため、最終的に何をしたいのかを正確に伝えるのは少し難しいですが、パーシャル (またはカリー化) を調べることもできます: http://jsbin.com/ifoqoj/1/edit

Function.prototype.partial = function(){
  var fn = this, args = Array.prototype.slice.call(arguments);
  return function(){
    var arg = 0;
    for ( var i = 0; i < args.length && arg < arguments.length; i++ )
      if ( args[i] === undefined )
        args[i] = arguments[arg++];
    return fn.apply(this, args);
  };
};

var c = function(a, b, c, callback) {
  console.log( a, b, c, callback )
};

var b = c.partial(1, 2, 3, undefined);

b(function(){})

John Resig の記事へのリンク: http://ejohn.org/blog/partial-functions-in-javascript/

于 2012-12-13T00:37:57.990 に答える
1

を使用してくださいprotagonist

var geoOpts = {...};

function geoSuccess(user){  // protagonizes for 'user'
  return function Success(pos){
    if(!pos || !pos.coords || !pos.coords.latitude || !pos.coords.longitude){ throw new Error('Geolocation Error: insufficient data.'); }

    var data = {pos.coords: pos.coords, ...};

    // now we have a callback we can turn into an object. implementation can use 'this' inside callback
    if(user){
      user.prototype = data;
      user.prototype.watch = watchUser;
      thus.User = (new user(data));
      console.log('thus.User', thus, thus.User);
    }
  }
}

function geoError(errorCallback){  // protagonizes for 'errorCallback'
  return function(err){
    console.log('@DECLINED', err);
    errorCallback && errorCallback(err);
  }
}

function getUserPos(user, error, opts){
  nav.geo.getPos(geoSuccess(user), geoError(error), opts || geoOpts);
}

基本的に、params を渡したい関数は、変数を渡すために呼び出すことができるプロキシになり、実際に実行したい関数を返します。

お役に立てれば!

于 2014-02-06T22:36:12.950 に答える
1

匿名ユーザーがこの追加情報を投稿しました:

この投稿で既に提供されているものに基づいて構築します-私が見た中で最もエレガントな解決策は、あなたの議論と文脈をカリー化することです:

function Class(a, b, c, d){
    console.log('@Class #this', this, a, b, c, d);
}

function Context(name){
    console.log('@Context', this, name);
    this.name = name;
}

var context1 = new Context('One');
var context2 = new Context('Two');

function curryArguments(fn) {
    var args = Array.prototype.slice.call(arguments, 1);
    return function bindContext() {
      var additional = Array.prototype.slice.call(arguments, 0);
      return fn.apply(this, args.concat(additional));
    };
}

var bindContext = curryArguments(Class, 'A', 'B');

bindContext.apply(context1, ['C', 'D']);
bindContext.apply(context2, ['Y', 'Z']);
于 2015-07-17T22:58:59.597 に答える
1

そんな単純な?

var b = (cb) => obj.c(1,2,3, cb)
b(function(){}) // insidde object

より一般的な解決策:

function original(a, b, c) { console.log(a, b, c) }
let tied = (...args) => original(1, 2, ...args)

original(1,2,3) // 1 2 3
tied(5,6,7) // 1 2 5

于 2016-11-08T12:06:49.957 に答える
-1

jQuery 1.9 では、プロキシ機能によってまさにその機能が提供されました。

jQuery 1.9 以降、コンテキストが null または未定義の場合、プロキシされた関数は、プロキシが呼び出されたのと同じ this オブジェクトで呼び出されます。これにより、 $.proxy() を使用して、コンテキストを変更せずに関数の引数を部分的に適用できます。

例:

$.proxy(this.myFunction, 
        undefined /* leaving the context empty */, 
        [precededArg1, precededArg2]);
于 2018-01-21T19:50:37.133 に答える
-6

Jquery の使用例:

代わりは:

for(var i = 0;i<3;i++){
    $('<input>').appendTo('body').click(function(i){
        $(this).val(i); // wont work, because 'this' becomes 'i'
    }.bind(i));
}

これを使って:

for(var i = 0;i<3;i++){
    $('<input>').appendTo('body').click(function(e){
        var i = this;
        $(e.originalEvent.target).val(i);
    }.bind(i));
}
于 2014-07-11T14:01:36.507 に答える