Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to bind function arguments without binding this?

Tags:

javascript

People also ask

How do you bind a function?

JavaScript Function bind()With the bind() method, an object can borrow a method from another object. The example below creates 2 objects (person and member).

What does bind () do in JavaScript?

bind is a method on the prototype of all functions in JavaScript. It allows you to create a new function from an existing function, change the new function's this context, and provide any arguments you want the new function to be called with.

What is the difference between call () and apply ()?

The Difference Between call() and apply() The difference is: The call() method takes arguments separately. The apply() method takes arguments as an array. The apply() method is very handy if you want to use an array instead of an argument list.

What is the alternative of binding this keyword in the constructor for callbacks?

First Method: We can use an arrow function in the render method where we are attaching the event handler.


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?

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.

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.


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

So we can define a function bindArgs that works like bind, except that only arguments are bound, but not the context (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

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.


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

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

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