Search code examples
javascriptfunctionfunctional-programmingthisecmascript-5

What object javascript function is bound to (what is its "this")?


I know that inside the function it is this.

var func = function {
    return this.f === arguments.callee; 
    // => true, if bound to some object
    // => false, if is bound to null, because this.f === undefined
}

var f = func; // not bound to anything;

var obj = {};
obj1.f = func; // bound to obj1 if called as obj1.f(), but not bound if called as func()

var bound = f.bind(obj2) // bound to obj2 if called as obj2.f() or as bound()

Edited:

You can't actually call obj2.f() as f doesn't become a property of obj2

edit end.

The question is: how to find the object, that the function is bound to, outside of this function?

I want to achieve this:

function g(f) {
  if (typeof(f) !== 'function') throw 'error: f should be function';

  if (f.boundto() === obj)
    // this code will run if g(obj1.f) was called
    doSomething(f);

  // ....

  if (f.boundto() === obj2)
    // this code will run if g(obj2.f) or g(bound) was called
    doSomethingElse(f);
}

and partial application without changing the object that the function is bound to:

function partial(f) {
   return f.bind(f.boundto(), arguments.slice(1));
}

Consensus:

You can't do it. Takeaway: use bind and this with great care :)


Solution

  • Partial Application

    You can do partial application:

    // This lets us call the slice method as a function
    // on an array-like object.
    var slice = Function.prototype.call.bind(Array.prototype.slice);
    
    function partial(f/*, ...args */) {
    
        if (typeof f != 'function')
            throw new TypeError('Function expected');
    
        var args = slice(arguments, 1);
    
        return function(/* ...moreArgs */) {
            return f.apply(this, args.concat(slice(arguments)));
        };
    
    }
    

    What Object is this Function Bound To?

    Additionally, there's a pretty straight-forward solution to the first part of your question. Not sure if this is an option for you, but you can pretty easily monkey-patch things in JS. Monkey-patching bind is totally possible.

    var _bind = Function.prototype.apply.bind(Function.prototype.bind);
    Object.defineProperty(Function.prototype, 'bind', {
        value: function(obj) {
            var boundFunction = _bind(this, arguments);
            boundFunction.boundObject = obj;
            return boundFunction;
        }
    });
    

    Just run that before any other scripts get run, and any script which uses bind, it will automatically add a boundObject property to the function:

    function f() { }
    var o = { };
    var g = f.bind(o);
    g.boundObject === o; // true
    

    (Note: I'm assuming you're in an ES5 environment above due to the fact that you're using bind.)