Max Koretskyi
Max Koretskyi

Reputation: 105439

How to identify whether a function is called as method or callback

I have an object which has a method. This method can be triggered as method on object or as callback function. What is the best way to determine how it's called? I've come up with a solution that I'm not sure is relible.

function Object() {
    this.method = function(elem) {
        if (elem.type !== undefined) {
            alert("we've got an event");
        } else {
            alert("it doens's seem to be an event");
        }
    }
}
var obj = new Object();
$('span').click(obj.method);
obj.method($('div'));

I've decided to edit my question a bit to point out that the question is not about 'this' parameter and how to bind function's context.

Upvotes: 0

Views: 198

Answers (8)

Max Koretskyi
Max Koretskyi

Reputation: 105439

I think this option is even better: I remove the check from the method and always expect an element to be passed. As a callback I pass the function that takes 'this' which will be a reference to the element and passes to my method:

$('span').click(function(){obj.method(this)};

Upvotes: 0

Craig
Craig

Reputation: 4399

If you want to bind a function to a context (object), then use something like this:

function createOnClick(obj, fn) {
    return function() {
        return fn.apply(obj, arguments);
    }
}

myObject = new Object();

$('button').click(createOnClick(myObject, myObject.method));

Now, when your method is called, 'this' will be a reference to the 'myObject' instance. This is commonly known and function binding and there are many API's that already do this. However, I am unfamiliar with JQuery, so you will need to refer to the documentation.

Upvotes: 0

JaredPar
JaredPar

Reputation: 754565

The best way to determine if this is a callback is to register a different function as the callback and explicitly pass down a value to say it was indeed a callback

function Object() {
    this.method = function(elem, isCallback) {
        if (isCallback) { 

        }
    } 
}

var obj = new Object();
$('span').click(function (elem) { obj.method(elem, isCallback); });
obj.method($('div'));

Upvotes: 0

Dietrich George
Dietrich George

Reputation: 114

This works. Pretty close to what you had.

function Object() {
    this.method = function(elem) {
        console.log(elem)
        if (elem.length != 0 && elem instanceof jQuery.Event) {
            alert("Accessed on Click");
        } else {
            alert("Not accessed on click.");
        }
    }
}
var obj = new Object();


$('span').click(obj.method);  // Accessed on click.


obj.method($('div')); // Not accesed on click.

http://jsfiddle.net/dietrichg/3mELA/

Upvotes: 0

Esailija
Esailija

Reputation: 140210

You should just have 2 different methods if they do different things.

If you really have the method do the same thing regardless of if it's called as a method or a callback, you can use $.proxy so that this is always the object:

function Object() {
    this.method = $.proxy( function(){

    }, this );
}
var obj = new Object();

Upvotes: 0

philipproplesch
philipproplesch

Reputation: 2127

If it's just about jQuery stuff (e.g. $.click), you could check if the event itself is passed to the function:

var handleClick = function () {
    var $this = $(this); // obj

    if (arguments.length > 0 && arguments[0] instanceof jQuery.Event) {
        alert('called as callback');
    } else {
        alert('called directly');
    }
};

$('button').click(handleClick);
handleClick();

Upvotes: 1

Scott Mermelstein
Scott Mermelstein

Reputation: 15397

I'm not sure why it should matter how the code was called. I bet that if you can articulate why it does matter, you'll see there's a parameter that should be passed to the function that lets the function know this. Then you could make a simple wrapper that will do it appropriately:

function MyObject() {
    this.method = function(randomParam1, randomParam2, calledThroughAlert) {
        // calledThroughAlert knows what you need to know.
    }
}

function callbackToMyObject() {
    obj.method('foo', 'bar', true);
}
var obj = new MyObject();
$('span').click(callbackToMyObject);
obj.method('bar', 'foo'); // defaults the calledThroughAlert param to false

Upvotes: 1

Matt
Matt

Reputation: 75307

The value of this inside method will be the Object instance (see Rocket's comment about naming) for all intents and purposes (unless the value was purposefully set via bind(), call() or apply()).

When executed as a method, the value of this will be the Object instance (again, unless altered via bind(), call() or apply()).

function Object() {
    var that = this;

    this.method = function(elem) {
        if (this !== that) {
            alert("we've got an event");
        } else {
            alert("it doens's seem to be an event");
        }
    }
}

You can see this working here http://jsfiddle.net/5WzEA/.

Upvotes: 0

Related Questions