Created
November 4, 2010 22:06
-
-
Save bryanforbes/663298 to your computer and use it in GitHub Desktop.
This is an attempt to explain what is happening behind the scenes with event handlers in ES3 and why IE leaks in one case and not another.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Global Object | |
// (§10.2.1) | |
// GO.scope_chain = [GO] | |
// GO._cache = _cache | |
var _cache = {}; | |
// Declaration (§13.2): | |
// CWanonfunc.[[Scope]] = GO.scope_chain.slice(0) (§13.2 step 7) | |
// GO.createWrapper = CWanonfunc() | |
var createWrapper = (function(){ // CWanonfunc | |
// Execution (§10.2.3): | |
// Activation Object creation (§10.1.6) | |
// CWanonfunc_AO.arguments = {} (§10.1.8) | |
// CWanonfunc_AO.id = id | |
// CWanonfunc_AO.createLookupHandler = createLookupHandler | |
// CWanonfunc_AO.createWrapper = createWrapper | |
// CWanonfunc.scope_chain = [CWanonfunc_AO].concat(CWanonfunc.[[Scope]]) == [CWanonfunc_AO, GO] | |
var id = 0; | |
// Declaration (§13.2): | |
// createLookupHandler.[[Scope]] = CWanonfunc.scope_chain.slice(0) == [CWanonfunc_AO, GO] (§13.2 step 7) | |
function createLookupHandler(id){ | |
// Execution (§10.2.3): | |
// Activation Object creation (§10.1.6) | |
// createLookupHandler_AO.arguments = {} (§10.1.8) | |
// createLookupHandler_AO.id = arguments[0] | |
// createLookupHandler_AO.handler = handler | |
// createLookupHandler.scope_chain = [createLookupHandler_AO].concat(createLookupHandler.[[Scope]]) == [createLookupHandler_AO, CWanonfunc_AO, GO] | |
// Declaration (§13.2): | |
// handler.[[Scope]] = createLookupHandler.scope_chain.slice(0) == [createLookupHandler_AO, CWanonfunc_AO, GO] (§13.2 step 7) | |
function handler(){ | |
// Execution (§10.2.3): | |
// Activation Object creation (§10.1.6) | |
// handler_AO.arguments = {} | |
// handler.scope_chain = [handler_AO].concat(handler.[[Scope]]) == [handler_AO, createLookupHandler_AO, CWanonfunc_AO, GO] | |
// id lookup (§10.1.4): | |
// check handler_AO, not found | |
// check createLookupHandler_AO, found | |
// _cache lookup (§10.1.4): | |
// check handler_AO, not found | |
// check createLookupHandler_AO, not found | |
// check CWanonfunc_AO, not found | |
// check GO, found | |
if(id in _cache && _cache[id]){ | |
_cache[id].handler.apply(_cache[id].element, arguments); | |
} | |
}; | |
} | |
// Declaration (§13.2): | |
// createWrapper.[[Scope]] = CWanonfunc.scope_chain.slice(0) == [CWanonfunc_AO, GO] (§13.2 step 7) | |
function createWrapper(elem, func){ | |
// Execution (§10.2.3): | |
// Activation Object creation (§10.1.6) | |
// createWrapper_AO.arguments = {} | |
// createWrapper_AO.elem = arguments[0] | |
// createWrapper_AO.func = arguments[1] | |
// createWrapper_AO.cid = id++ | |
// createWrapper_AO.wrapper = createLookupHandler(cid) | |
// createWrapper.scope_chain = [createWrapper_AO].concat(createWrapper.[[Scope]]) == [createWrapper_AO, CWanonfunc_AO, GO] | |
// id lookup (§10.1.4): | |
// check createWrapper_AO, not found | |
// check CWanonfunc_AO, found | |
// createLookupHandler lookup (§10.1.4): | |
// check createWrapper_AO, not found | |
// check CWanonfunc_AO, found | |
var cid = id++, | |
wrapper = createLookupHandler(cid); | |
// _cache lookup (§10.1.4): | |
// check createWrapper_AO, not found | |
// check CWanonfunc_AO, not found | |
// check GO, found | |
_cache[cid] = { | |
handler: wrapper, | |
element: elem | |
}; | |
return wrapper; | |
} | |
return createWrapper; | |
})(); | |
// createWrapper.[[Scope]] == [CWanonfunc_AO, GO] | |
// Declaration (§13.2): | |
// anonfunc.[[Scope]] = GO.scope_chain.slice(0) (§13.2 step 7) | |
(function(){ // anonfunc | |
// Execution (§10.2.3): | |
// Activation Object creation (§10.1.6) | |
// anonfunc_AO.arguments = {} | |
// anonfunc_AO.elem = elem | |
// anonfunc_AO.LeakFunc = LeakFunc | |
// anonfunc.scope_chain = [anonfunc_AO].concat(anonfunc.[[Scope]]) == [anonfunc_AO, GO] | |
// This sets anonfunc_AO.elem | |
var elem = document.getElementById("someElement"); | |
// Declaration (§13.2): | |
// LeakFunc.[[Scope]] = anonfunc.scope_chain.slice(0) == [anonfunc_AO, GO] (§13.2 step 7) | |
function LeakFunc(){ | |
// Execution (§10.2.3): | |
// Activation Object creation (§10.1.6) | |
// LeakFunc_AO.arguments = {} | |
// LeakFunc.scope_chain = [LeakFunc_AO].concat(LeakFunc.[[Scope]]) == [LeakFunc_AO, anonfunc_AO, GO] | |
} | |
// Attach: anonfunc_AO.elem.onclick = anonfunc_AO.LeakFunc | |
// Leak: lookup through activation object through scope chain | |
// LeakFunc.scope_chain = [ | |
// LeakFunc_AO, | |
// anonfunc_AO: { | |
// elem: { | |
// onclick: LeakFunc | |
// } | |
// }, | |
// GO | |
// ] | |
elem.attachEvent("onclick", LeakFunc); | |
// Attach: anonfunc_AO.elem.onclick = anonfunc_AO.anonHandler | |
// No leak: lookup through global object through scope chain | |
// anonHandler.scope_chain = [ | |
// handler_AO, | |
// createLookupHandler_AO, | |
// CWanonfunc_AO, | |
// GO: { | |
// _cache: { | |
// 0: { | |
// element: { | |
// onclick: anonHandler | |
// } | |
// } | |
// } | |
// } | |
// ] | |
elem.attachEvent("onclick", createWrapper(function(){})); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment