Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 430
esp Avatar asked Jan 13 '13 19:01

esp


People also ask

What is bound function in JavaScript?

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 is a function object in JavaScript?

JavaScript functions are a special type of objects, called function objects. A function object includes a string which holds the actual code -- the function body -- of the function. The code is literally just a string.

What are the 3 types of functions in JavaScript?

There are 3 ways of writing a function in JavaScript: Function Declaration. Function Expression. Arrow Function.

How do you call a function inside an object in JavaScript?

You can call a function inside an object by declaring the function as a property on the object and invoking it, e.g. obj. sum(2, 2) . An object's property can point to a function, just like it can point to a string, number or other values. Copied!


4 Answers

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

like image 193
Nathan Wall Avatar answered Sep 21 '22 15:09

Nathan Wall


A function in javascript is not technically bound to anything. It may be declared as a property of an object as in:

var obj = {
    fn: function() {}
}
obj.fn();

But, if you get the function into it's own variable by itself, it is not bound to any particular object.

For example, if you did this:

var obj = {
    fn: function() {}
}
var func = obj.fn;
func();

Then, when you call func() which in turn executes the fn() function, it will have no association with obj at all when it is called. Associating an object with a function is done by the caller of the function. It is not a property of the function.

If one were to use fn.bind(obj), that creates a new function that just internally executes a call to obj.fn(). It doesn't magically add any new capabilities to javascript. In fact, you can see a polyfill for .bind() to see how it works here on MDN.


If you are expecting this to always be a particular object no matter how a function is called, that is not how javascript works. Unless a function is actually a shim that forces an association with a hard-wird object when it's called (what .bind() does), then a function doesn't have a hard-wired association. The association is done by the caller based on how it calls the function. This is different than some other languages. For example, in C++, you can't call a function without having the right object to associate with it at call time. The language simply won't resolve the function call and you get a compile error.

If you are branching on types in javascript, then you are probably not using the object-oriented capabilities of the language properly or to your best advantage.

like image 23
jfriend00 Avatar answered Sep 24 '22 15:09

jfriend00


Instead of binding the function func to the objects, why not try treating func as an object, that can hold obj1 and obj2 as its properties?

For example:

var func = function {
    this.object; // Could be obj1 or obj2
    return this.f === arguments.callee;
    // => true, if this.object is not null
}

var f = func;

f.object = obj1; // or func.object = obj2;

You can also write a function that handles whether or not the object is obj1 or obj2:

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

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

The reason is that you want to treat obj1 and obj2 as a property of the function f. However, when you bind, you are adding the function as a property of either obj1 or obj2. It's possible to bind the function to multiple objects, so it doesn't make sense to look for THE one object to which you bound the function; because you're adding the function as a subset of the object.

In this case, since you want to treat the object as a subset of the function, it might make sense to add a property into the function that can hold obj1 or obj2.

like image 31
Stegrex Avatar answered Sep 23 '22 15:09

Stegrex


If you are the one doing the bind, you can add a field to the function to record the this for later testing.

var that = "hello";
var xyz = function () { console.log(this); }.bind(that);
xyz.that = that;

// xyz is callable as in xyz(), plus you can test xyz.that without calling
like image 25
Erik Eidt Avatar answered Sep 25 '22 15:09

Erik Eidt