There's two parts to your question which I'll try to answer. The first question:
How can get the name of the function bound to my element?
This one is fairly straight forward, and you're actually on the right path with your fiddle. When you bind an event handler, the handler's event type is added to jQuery's internal _data
object. So, for instance, if you do:
$('div').on('click', function() { ... })
Then internally, jQuery will create an object {}
and add a key, click
to that. Like this:
{'click': []}
The key points to an array of objects, which are all the event handlers you've bound with the click
type.
If you were to add a custom event like this:
$('div').on('myfancyhandler', function() {...})
And called $._data($('div')[0], 'events')
, you would see an object returned like:
{'myfancyhandler': []}
So, when you call $._data( el , 'events')
, you can access the handler property (which points to an array of your handlers) like this:
// Bind two event handlers - click and our custom myfancyhandler event
$('div').on('click myfancyhandler', function() { });
// Returns object {click: [], myfancyhandler: []}
var handlers = $._data($('div')[0], 'events');
// Access handler (function passed for callback)
var handler = handlers.click[0].handler; // dot notation, square bracket works too
Now, say you do something like this:
$('div').on('click', function(){ alert(1) });
$('div').on('click', function(){ alert(2) });
var handlers = $._data($('div')[0], 'events');
The _data
object would have one click property with two items in the array, like this:
{click: [
{
handler: function() { alert(1) }
/* additional properties */
},
{
handler: function() { alert(2) }
/* additional properties */
}
]}
Visually (in our console), you could see that the first object is the function that alerts 1, and the second function alerts 2. But, what if you needed to programmatically check? For that, we would need to name our anonymous functions
, like so:
$('div').on('click', function alert1(){ alert(1) });
$('div').on('click', function alert2(){ alert(2) });
var handlers = $._data($('div')[0], 'events');
Which would return us:
{click: [
{
handler: function alert1() { alert(1) }
/* additional properties */
},
{
handler: function alert2() { alert(2) }
/* additional properties */
}
]}
Which we could then check (and get the name) like this:
var handlers = $._data($('div')[0], 'events');
handlers.click.forEach(function(obj, idx){
console.log(obj.handler.name);
});
That would output:
console
> alert1
> alert2
In addition, you could pass a reference to the function like this:
function ourCoolHandler() { .. does something .. }
// Bind our cool handler
$('div').on('keyup', ourCoolHandler);
// Get event object
var evtObj = $._data($('div')[0], 'events')
// Get function name from handler object
console.log(evtObj.keyup[0].handler.name) // ourCoolHandler
As for your second question, which is:
Also, if the function is actually bound to a parent element, is there anyway to access the functions name if I only have the the child?
What I think you're referring to is jQuery's event delegation
. Something like this:
$('#parentElement').on('click', '#childElement', function() { .. do something } );
And then somehow get the function named based on #childElement
. The short answer is no, this can't be done. You're right when you say Surely these must be stored internally somewhere by jQuery.
In fact, let's walk through what happens when we do this:
$('#parentElement').on('click', '#childElement', function doSomething() { .. do something } );
jQuery finds the #parentElement
and registers a click handler. But, it sees that you want to only handle the click event when the selector
is #childElement
. (If this is omitted, the event is always triggered.) Now, if we do something like this:
$._data($('#childElement')[0], 'events');
nothing will be returned. However, if we do something like this:
$._data($('#parentElement')[0], 'events');
an object is returned with our click handler. Something that looks like this:
{
click:
// 0 index array
0: {
handler: function doSomething,
selector: '#childElement'
}
delegateCount: 1
}
As you can see in the returned object, this is where the child element is stored by jQuery. The events are filtered when delegateCount
is greater than 0, and it's filtered against the selector
passed in.
Now earlier I said the short answer is no. The longer answer is you could - you could (in theory) traverse up the DOM and check each element to see if it has a event object, has a delegateCount, and if the selector matches the child element. That'd be a lot of logic to implement, though.
Finally, one last trick: You can see all event handlers bound to an element in Chrome Developer Tool. Open it up, click an element, and choose the "Event Listeners" tab on the right. If there's an event handler bound, it should show up there. Something like this:

Good luck!