如何绑定函数参数而不绑定这个?

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

对此我还是新的,对于混淆抱歉。

谢谢!

你可以做到这一点,但最好避免把它看作是“绑定”,因为这是用来设置“this”值的术语。 也许把它想象成“包装”一个函数的参数?

你所做的是创build一个函数,通过闭包内置所需的参数:

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

希望我在那里得到了语法。 它所做的就是创build一个名为withWrappedArguments()的函数(这是一个迂回的函数,它是一个赋予variables的匿名函数),你可以在任何地方任何时候调用它,并且总是会用actualArg1Value和actualArg2Value以及其他任何你想要的东西那里。 如果需要,您也可以在通话时接受更多的参数。 最后的大括号之后的秘诀是括号。 这些使外部函数立即执行,并传递值,并生成稍后可调用的内部函数。 传递的值在函数生成时被冻结。

这实际上是绑定所做的事情,但是这种方式明确地说明,绑定的参数只是局部variables的闭包,并且不需要改变这种行为。

在本地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; }; 

在ES6中,使用rest参数和扩展运算符很容易完成。

所以我们可以定义一个像bind一样工作的bindArgs函数,除了只绑定参数,而不是上下文( this )。

 Function.prototype.bindArgs = function (...boundArgs) { let context = this; return function(...args) { return context.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 ,并在绑定的参数后面附加额外的参数。 返回值只是简单的转发。

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

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

要确切地说明你最终想做的事情有点难,因为这个例子有些武断,但是你可能想看看partials(或currying): 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/

使用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函数成为一个代理,你可以调用传递一个variables,它返回你真正想做的东西的function。

希望这可以帮助!

匿名用户发布了这个额外的信息:

基于这篇文章中已经提供的内容,我所见过的最优雅的解决scheme是咖喱你的论点和上下文:

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

那么你给的例子,这将做

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

如果你想保护参数的shell:

 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) 

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

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

这是更好的方法。

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

为什么不使用函数的包装来保存这个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 = (cb) => obj.c(1,2,3, cb) b(function(){}) // insidde object 

更一般的解决scheme

 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使用案例:

代替:

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