jQuery Audit
is a Chrome Developer Tools extension for debugging auditing jQuery — it creates a sidebar in the Elements panel
containing jQuery delegated events, internal data, and more, as live DOM nodes
, functions
, and objects
.
DOM nodes
, functions
, and objects
jQuery Audit
sidebar behave like objects in the Sources panel
→ Scope Variables
sidebar. You can right-click on a function
and goto "Show Function Definition", or hover over a DOM node
to highlight it in the document, as well as right-clicking it to "Reveal in Elements Panel".document
and window
objectsdocument
and the window
objects don't have representations in the Elements panel
but can nonetheless be event targets and/or have associated jQuery data. jQuery Audit
adds two comment nodes above the <!DOCTYPE>
to represent them. The <!--@(document)-->
as a stand-in for the document
object, and the <!--@(window)-->
as a stand-in for the window
object. Select either to audit the represented object in the jQuery Audit
sidebar.Requirements: jQuery Audit
does a typeof window.jQuery === 'function'
whenever a node
is selected. If it can't find a jQuery
function in the global scope, the sidebar will display Error: "@(window.jQuery is missing)"
.
Tip: Text wrapped in @(...)
are "messages" from jQuery Audit
. This was the compromise made to get live objects in the sidebar and be able to show informative messages.
@(this element)
Data
$(element).data()
. jQuery Audit
doesn't invoke .data()
because calling it creates a data object in jQuery's internal store if one doesn't already exist for that element. Instead, jQuery Audit
directly looks in the internal store for the data object and returns it. If there isn't one, you'll see @(none)
, or if it's an empty object you'll see @(empty Object)
.Events([number_of_events])
Internal Data
→ events
). For each event name, there is a corresponding jQuery event object associated with it, that has:
delegator
: The ancestor element that delegates the event, or @(this element)
when the event is directly bound to the element and there is no delegation.handler
: The function that handles the event. More often than not, the handler
is a bound function and not directly the function that does the "work". The section below on Finding bound handlers shows you where common binder functions store the bound function.Internal Data
$._data(element)
. This is not the same as the data object from $(element).data()
, though the data object is kept here in the internal store.dataset
HTMLElement.dataset
. This is not the same as Data above, but closely related to it. HTMLElement.dataset
contains the raw data-*
attributes. While Data is the parsed content of any data-*
attributes jQuery found on the element along with any other arbitrary information. (jQuery converts Boolean
, Number
and JSON
in data-*
attributes when you call .data()
).own HTML
innerHTML
from the outerHTML
of an element. This helps debug character encoding issues, since what the Elements panel
shows is a decoded "pretty" version of the HTML and not the actual HTML.Often event handlers
are bound functions. In these cases, the function under Events
→ event_name
→ handler
is the binder
function and not the bindee
. Depending on the binder
used, the bindee
function is usually near by.
_.bind
from Lo-DashExpand the handler
function followed by the __bindData__
property. In this array, the first element is the bindee
function, the other elements contain the this
context and any parameters to be partially applied. Older versions of Lo-Dash might not have this structure.
_.bind
from Underscore and native Function.prototype.bind
Underscore uses to the native bind
function. A clear sign that the binder
is the native bind
function is function () { [native code] }
for a handler
. Expand the handler
to locate the bindee
function is under [[TargetFunction]]
. The this
context is found in [[BoundThis]]
and any parameters to be partially applied are in [[BoundArgs]]
.
$.proxy
from jQueryWith $.proxy
the bindee
can't be found as a property on the binder
but rather in a Closure
. Expand the handler
, followed by <function scope>
and then the inner-most Closure
. One of the variables in this scope contains the bindee
- the name of the variable that contains the bindee
will likely vary because of minification.
Does jQuery Audit
work with <iframe>'s
?
Yes, if the
<iframe>
has a jQuery function (regardless of the parent having jQuery or not) and it's not restricted by the same-origin policy.
How do I remove <!--@(document)-->
and <!--@(window)-->
?
Run
jQueryAudit()
in the console. When you close the developer tools the twocomment nodes
are removed and thejQueryAudit
object is removed.
Why exactly the @(...)
?
The content of a
SidebarPane
can be an HTML page, a JSON object, or "the result of an expression". An HTML page, nor a JSON object, have the ability to display "live" objects. The reason for making this extension was so that I could find a delegated event and be able to use "Show Function Definition" on the handler. For that effect, the contents of the sidebar is actually "the result of an expression" with a lot of trickery to make it look not-so-ugly. So, to differentiate between actual object data and informational messages I went with@(...)
so it wouldn't be easily confused with string data.
Why the name Audit?
I am a lawyer. Yes, really. Went to law school, passed the bar, and I'm a fully admitted member of the New York State Bar Association. So, yeah, that's why Audit came to mind when I was thinking of a name.
Disclaimer: I am not related to the jQuery project.