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

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

我还是个新手,抱歉搞混了。

谢谢!

82740 次浏览

确切地说出您最终想要做什么有点困难,因为这个示例有点随意,但是您可能需要查看部分(或局部套用) : 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/

在本机 bind中,result 函数中的 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;
};

在 ES6中,使用 剩余参数扩散算符扩散算符很容易做到这一点。

因此,我们可以定义一个类似于 bind的函数 bindArgs,只不过只绑定参数,而不绑定上下文(this)。

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

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

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

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

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

希望我能理解你的语法。它所做的是创建一个名为 withWrappedArguments ()的函数(为了显得迂腐,它是一个分配给变量的匿名函数) ,你可以在任何时间、任何地点调用该函数,并且始终使用 realArg1Value 和 realArg2Value 进行操作,以及任何你想要放入其中的东西。如果需要,还可以让它在调用时接受进一步的参数。秘诀在于最后一个括号后面的括号。这会导致立即使用传递的值执行外部函数,并生成以后可以调用的内部函数。然后在生成函数时冻结传递的值。

这实际上就是 bind 所做的事情,但是通过这种方式,可以清楚地看到被包装的参数只是局部变量上的闭包,不需要改变它的行为。

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

使用 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 的函数变成了一个代理,你可以调用它来传递一个变量,它返回你实际想要做的事情。

希望这个能帮上忙!

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

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

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

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

在这篇文章已经提供的基础上——我所见过的最优雅的解决方案是 咖喱你的论点和上下文:

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

为什么不使用函数周围的包装器将其保存为 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);

对于你给出的例子来说,这个就够了

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

如果要保证参数的封闭性:

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)

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

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

这样更好。

就这么简单?

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

使用 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.

JQuery 1.9使用代理函数带来了这个特性。

从 jQuery 1.9开始,当上下文为 null 或未定义时,代理函数将使用与代理调用相同的 this 对象进行调用。这允许 $。在不改变上下文的情况下部分应用函数的参数。

例如:

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

也许你想绑定参考的 这个在最后,但你的代码:-

var c = function(a, b, c, callback) {};
var b = c.bind(null, 1, 2, 3);

已经对实例 这个应用了绑定,以后您不能更改它。 我建议也使用 reference 作为参数,如下所示:-

var c = function(a, b, c, callback, ref) {
var self = this ? this : ref;
// Now you can use self just like this in your code
};
var b = c.bind(null, 1, 2, 3),
newRef = this, // or ref whatever you want to apply inside function c()
d = c.bind(callback, newRef);

我正在使用这个函数:

function bindArgs(func, ...boundArgs) {
return function (...args) {
return func(...boundArgs, ...args);
};
}
// use
const deleteGroup = bindArgs(this.props.deleteGroup, "gorupName1");