Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
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.
// 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