如何绑定函数参数而不绑定它?

时间:2022-11-07 13:48:25

In Javascript, how can I bind arguments to a function without binding the this parameter?

在Javascript中,如何在不绑定this参数的情况下将参数绑定到函数?

For example:

例如:

//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?

How can I avoid the side-effect of having to bind the function's scope (e.g. setting this = null) as well?

如何避免必须绑定函数范围的副作用(例如设置this = null)?

Edit:

编辑:

Sorry for the confusion. I want to bind arguments, then be able to call the bound function later and have it behave exactly as if I called the original function and passed it the bound arguments:

对困惑感到抱歉。我想绑定参数,然后能够稍后调用绑定函数并使其行为完全像我调用原始函数并将其传递给绑定参数:

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?

I'm still new at this, sorry for the confusion.

我仍然是新人,抱歉这令人困惑。

Thanks!

谢谢!

14 个解决方案

#1


22  

You can do this, but best to avoid thinking of it as "binding" since that is the term used for setting the "this" value. Perhaps think of it as "wrapping" the arguments into a function?

您可以这样做,但最好不要将其视为“绑定”,因为这是用于设置“this”值的术语。也许可以把它看作是将参数“包装”成一个函数?

What you do is create a function that has the desired arguments built into it via closures:

你要做的是创建一个函数,通过闭包在其中内置所需的参数:

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

Hope I got the syntax right there. What it does is create a function called withWrappedArguments() (to be pedantic it is an anonymous function assigned to the variable) that you can call any time any where and will always act with actualArg1Value and actualArg2Value, and anything else you want to put in there. You can also have it accept further arguments at the time of the call if you want. The secret is the parentheses after the final closing brace. These cause the outer function to be immediately executed, with the passed values, and to generate the inner function that can be called later. The passed values are then frozen at the time the function is generated.

希望我能在那里得到语法。它的作用是创建一个名为withWrappedArguments()的函数(迂腐,它是一个分配给变量的匿名函数),你可以随时随地调用它,并且总是使用actualArg1Value和actualArg2Value以及你想要放入的任何其他内容。那里。如果需要,您还可以在通话时接受进一步的参数。秘密是最后一次结束后的括号。这些导致使用传递的值立即执行外部函数,并生成可以在以后调用的内部函数。然后在生成函数时冻结传递的值。

This is effectively what bind does, but this way it is explicit that the wrapped arguments are simply closures on local variables, and there is no need to change the behaviour of this.

这实际上是绑定所做的,但是这样显然包装的参数只是对局部变量的闭包,并且不需要改变它的行为。

#2


16  

In the native bind method the this value in the result function is lost. However, you can easily recode the common shim not to use an argument for the context:

在本机绑定方法中,结果函数中的此值将丢失。但是,您可以轻松地重新编码常见的垫片,而不是使用上下文的参数:

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;
};

#3


15  

In ES6, this is easily done using rest parameters in conjunction with the spread operator.

在ES6中,可以使用rest参数和spread运算符轻松完成。

So we can define a function bindArgs that works like bind, except that only arguments are bound, but not the context (this).

所以我们可以定义一个与bind类似的函数bindArgs,除了只绑定参数,但不绑定上下文(this)。

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

Then, for a specified function foo and an object obj, the statement

然后,对于指定的函数foo和对象obj,该语句

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

is equivalent to

相当于

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

where only the first and second arguments are bound to bar, while the context obj specified in the invocation is used and extra arguments are appended after the bound arguments. The return value is simply forwarded.

其中只有第一个和第二个参数绑定到bar,而使用调用中指定的上下文obj,并在绑定参数后追加额外的参数。返回值只是转发。

#4


7  

One more tiny implementation just for fun:

一个小小的实现只是为了好玩:

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);
    };
}

How to use:

如何使用:

function onWriteEnd(evt) {}
var myPersonalWriteEnd = bindWithoutThis(onWriteEnd, "some", "data");

#5


3  

var b = function() {
    return c(1,2,3);
};

#6


2  

It's a bit hard to tell exactly what you ultimately want to do because the example is sort of arbitrary, but you may want to look into partials (or currying): http://jsbin.com/ifoqoj/1/edit

要确切地告诉你最终想要做什么有点难,因为这个例子有点武断,但你可能想看看部分(或讨论):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(){})

Link to John Resig's article: http://ejohn.org/blog/partial-functions-in-javascript/

链接到John Resig的文章:http://ejohn.org/blog/partial-functions-in-javascript/

#7


1  

Use a 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);
}

Basically, the function you want to pass params to becomes a proxy which you can call to pass a variable, and it returns the function you actually want to do stuff.

基本上,你想要传递params的函数成为一个代理,你可以调用它来传递一个变量,然后它返回你真正想做的东西。

Hope this helps!

希望这可以帮助!

#8


1  

An anonymous user posted this additional info:

匿名用户发布了以下附加信息:

Building on what has already been provided in this post -- the most elegant solution I've seen is to Curry your arguments and context:

基于这篇文章中已经提供的内容 - 我见过的最优雅的解决方案是Curry你的论点和背景:

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']);

#9


1  

Well for the exemple you gave, this will do

那么你给的例子就是这样的

var b= function(callback){
        return obj.c(1,2,3, callback);
};

If you want to guarenty enclosure of the parameters :

如果你想要guarenty参数的封闭:

var b= (function(p1,p2,p3, obj){
        var c=obj.c;
        return function(callback){
                return c.call(obj,p1,p2,p3, callback);
        }
})(1,2,3,obj)

But if so you should just stick to your solution:

但如果是这样,你应该坚持你的解决方案:

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

It's the better way.

这是更好的方式。

#10


1  

Simple like that?

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

More general solution:

更一般的解决方案

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

#11


0  

Why not use a wrapper around the function to save this as mythis ?

为什么不在函数周围使用包装器将其保存为mythis?

function mythis() {
  this.name = "mythis";
  mythis = this;
  function c(a, b) {
    this.name = "original";
    alert('a=' + a + ' b =' + b + 'this = ' + this.name + ' mythis = ' + mythis.name);
    return "ok";
  }    
  return {
    c: c
  }
};

var retval = mythis().c(0, 1);

#12


0  

Using LoDash you can use the _.partial function.

使用LoDash可以使用_.partial函数。

const f  = function (a, b, c, callback) {}

const pf = _.partial(f, 1, 2, 3)  // f has first 3 arguments bound.

pf(function () {})                // callback.

#13


0  

jQuery 1.9 brought exactly that feature with the proxy function.

jQuery 1.9使用代理功能带来了这个功能。

As of jQuery 1.9, when the context is null or undefined the proxied function will be called with the same this object as the proxy was called with. This allows $.proxy() to be used to partially apply the arguments of a function without changing the context.

从jQuery 1.9开始,当上下文为null或未定义时,将使用与调用代理相同的此对象调用代理函数。这允许$ .proxy()用于部分应用函数的参数而不更改上下文。

Example:

例:

$.proxy(this.myFunction, 
        undefined /* leaving the context empty */, 
        [precededArg1, precededArg2]);

#14


-5  

Jquery use case:

Jquery用例:

instead:

代替:

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

use this:

用这个:

for(var i = 0;i<3;i++){
    $('<input>').appendTo('body').click(function(e){
        var i = this;
        $(e.originalEvent.target).val(i);
    }.bind(i));
}

#1


22  

You can do this, but best to avoid thinking of it as "binding" since that is the term used for setting the "this" value. Perhaps think of it as "wrapping" the arguments into a function?

您可以这样做,但最好不要将其视为“绑定”,因为这是用于设置“this”值的术语。也许可以把它看作是将参数“包装”成一个函数?

What you do is create a function that has the desired arguments built into it via closures:

你要做的是创建一个函数,通过闭包在其中内置所需的参数:

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

Hope I got the syntax right there. What it does is create a function called withWrappedArguments() (to be pedantic it is an anonymous function assigned to the variable) that you can call any time any where and will always act with actualArg1Value and actualArg2Value, and anything else you want to put in there. You can also have it accept further arguments at the time of the call if you want. The secret is the parentheses after the final closing brace. These cause the outer function to be immediately executed, with the passed values, and to generate the inner function that can be called later. The passed values are then frozen at the time the function is generated.

希望我能在那里得到语法。它的作用是创建一个名为withWrappedArguments()的函数(迂腐,它是一个分配给变量的匿名函数),你可以随时随地调用它,并且总是使用actualArg1Value和actualArg2Value以及你想要放入的任何其他内容。那里。如果需要,您还可以在通话时接受进一步的参数。秘密是最后一次结束后的括号。这些导致使用传递的值立即执行外部函数,并生成可以在以后调用的内部函数。然后在生成函数时冻结传递的值。

This is effectively what bind does, but this way it is explicit that the wrapped arguments are simply closures on local variables, and there is no need to change the behaviour of this.

这实际上是绑定所做的,但是这样显然包装的参数只是对局部变量的闭包,并且不需要改变它的行为。

#2


16  

In the native bind method the this value in the result function is lost. However, you can easily recode the common shim not to use an argument for the context:

在本机绑定方法中,结果函数中的此值将丢失。但是,您可以轻松地重新编码常见的垫片,而不是使用上下文的参数:

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;
};

#3


15  

In ES6, this is easily done using rest parameters in conjunction with the spread operator.

在ES6中,可以使用rest参数和spread运算符轻松完成。

So we can define a function bindArgs that works like bind, except that only arguments are bound, but not the context (this).

所以我们可以定义一个与bind类似的函数bindArgs,除了只绑定参数,但不绑定上下文(this)。

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

Then, for a specified function foo and an object obj, the statement

然后,对于指定的函数foo和对象obj,该语句

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

is equivalent to

相当于

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

where only the first and second arguments are bound to bar, while the context obj specified in the invocation is used and extra arguments are appended after the bound arguments. The return value is simply forwarded.

其中只有第一个和第二个参数绑定到bar,而使用调用中指定的上下文obj,并在绑定参数后追加额外的参数。返回值只是转发。

#4


7  

One more tiny implementation just for fun:

一个小小的实现只是为了好玩:

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);
    };
}

How to use:

如何使用:

function onWriteEnd(evt) {}
var myPersonalWriteEnd = bindWithoutThis(onWriteEnd, "some", "data");

#5


3  

var b = function() {
    return c(1,2,3);
};

#6


2  

It's a bit hard to tell exactly what you ultimately want to do because the example is sort of arbitrary, but you may want to look into partials (or currying): http://jsbin.com/ifoqoj/1/edit

要确切地告诉你最终想要做什么有点难,因为这个例子有点武断,但你可能想看看部分(或讨论):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(){})

Link to John Resig's article: http://ejohn.org/blog/partial-functions-in-javascript/

链接到John Resig的文章:http://ejohn.org/blog/partial-functions-in-javascript/

#7


1  

Use a 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);
}

Basically, the function you want to pass params to becomes a proxy which you can call to pass a variable, and it returns the function you actually want to do stuff.

基本上,你想要传递params的函数成为一个代理,你可以调用它来传递一个变量,然后它返回你真正想做的东西。

Hope this helps!

希望这可以帮助!

#8


1  

An anonymous user posted this additional info:

匿名用户发布了以下附加信息:

Building on what has already been provided in this post -- the most elegant solution I've seen is to Curry your arguments and context:

基于这篇文章中已经提供的内容 - 我见过的最优雅的解决方案是Curry你的论点和背景:

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']);

#9


1  

Well for the exemple you gave, this will do

那么你给的例子就是这样的

var b= function(callback){
        return obj.c(1,2,3, callback);
};

If you want to guarenty enclosure of the parameters :

如果你想要guarenty参数的封闭:

var b= (function(p1,p2,p3, obj){
        var c=obj.c;
        return function(callback){
                return c.call(obj,p1,p2,p3, callback);
        }
})(1,2,3,obj)

But if so you should just stick to your solution:

但如果是这样,你应该坚持你的解决方案:

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

It's the better way.

这是更好的方式。

#10


1  

Simple like that?

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

More general solution:

更一般的解决方案

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

#11


0  

Why not use a wrapper around the function to save this as mythis ?

为什么不在函数周围使用包装器将其保存为mythis?

function mythis() {
  this.name = "mythis";
  mythis = this;
  function c(a, b) {
    this.name = "original";
    alert('a=' + a + ' b =' + b + 'this = ' + this.name + ' mythis = ' + mythis.name);
    return "ok";
  }    
  return {
    c: c
  }
};

var retval = mythis().c(0, 1);

#12


0  

Using LoDash you can use the _.partial function.

使用LoDash可以使用_.partial函数。

const f  = function (a, b, c, callback) {}

const pf = _.partial(f, 1, 2, 3)  // f has first 3 arguments bound.

pf(function () {})                // callback.

#13


0  

jQuery 1.9 brought exactly that feature with the proxy function.

jQuery 1.9使用代理功能带来了这个功能。

As of jQuery 1.9, when the context is null or undefined the proxied function will be called with the same this object as the proxy was called with. This allows $.proxy() to be used to partially apply the arguments of a function without changing the context.

从jQuery 1.9开始,当上下文为null或未定义时,将使用与调用代理相同的此对象调用代理函数。这允许$ .proxy()用于部分应用函数的参数而不更改上下文。

Example:

例:

$.proxy(this.myFunction, 
        undefined /* leaving the context empty */, 
        [precededArg1, precededArg2]);

#14


-5  

Jquery use case:

Jquery用例:

instead:

代替:

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

use this:

用这个:

for(var i = 0;i<3;i++){
    $('<input>').appendTo('body').click(function(e){
        var i = this;
        $(e.originalEvent.target).val(i);
    }.bind(i));
}