Javascript Execution Context, Counter-Intuitive Scope Chain inside Mouse Handlers
Here is an interesting case of scope chain not explained in lot of documents which I am finding it difficult to understand. If someone can take time to read the well commented code below and explain how the variable is getting resolved, it would be very nice
I have two rectangles (DIVs) on a document. I register event listeners for mousedown on both and within the mousedown listener I register mouseup. Strange thing is happening within the listener of mouseup.
Two execution context are created by calling testfunc twice with different value of arguments:
window.onload = function() {
test_func("horizontal"); // First Execution context
test_func("vertical"); // Second Execution Context
}
Within the mouseup listener of the first rectangle(horizontal) the second execution context (vertical) is being used which is counter intuitive:
function test_func(dir) {
var X = 9; // variable which helps to track the execution contexts
if(dir === "horizontal")
X = 1; // leave at 9 if vertical
mouseup_vert = function() {}
mouseup_horiz = function() {
// Here the value of X I am getting is 9 whereas I am expecting 11
// QUESTION: Why I am getting the second execution context??
}
mousedown开发者_StackOverflow_vert = function() {
// As expected the value of X here is 9
X=99;
// set X to 99 to check if during mouseup same exec context is picked
document.addEventListener("mouseup", mouseup_vert, false);
}
mousedown_horiz = function() {
// As expected value of X is 1, so using first execution context
X=11;
// set this to check if during mouseup I get a value of 11
document.addEventListener("mouseup", mouseup_horiz, false);
}
if (dir === "horizontal") {
e = document.getElementById("horiz");
e.addEventListener("mousedown", mousedown_horiz, false);
} else {
e = document.getElementById("vert");
e.addEventListener("mousedown", mousedown_vert, false);
}
}
It is because your variables referencing the functions are not declared with var
, so they're global.
They're being overwritten with the second call, which closes around X
with the value 9
.
EDIT: Here's what is effectively happening. For simplicity, I'm making all variables in the same scope.
// "a" is referencing a function.
var a = function() { alert( 'a' ); };
// "b" is referencing the same function that "a" is referencing.
var b = a;
// The reference "a" holds to the function is being overwritten with a
// reference to a new function.
a = function() { alert( "I'm a new function" ); };
// "c" is referencing the same function that "a" is referencing (the new one).
var c = a;
// So what is "b" referencing? It is still the original function, because it
// picked up that reference *before* the original reference "a" held was
// overwritten.
b(); // alerts 'a'
...or to make the code a little more specific to your code:
// reference a function
var mouseup_vert = function() { alert( "I'm a mouseup function." ); };
// reference a function
var mousedown_vert = function() {
// When this function is invoked, add a listener using
// whatever function is referenced by mouseup_vert
document.addEventListener( "mouseup", mouseup_vert, false);
};
// The function currently referenced by "mousedown_vert" is passed here
// as the event handler.
document.addEventListener("mousedown", mousedown_vert, false);
// Overwrite "mouseup_vert" just for kicks.
mouseup_vert = function() { alert( "I'm a completely different function." ); };
// NOW trigger a "mousedown" event. What happens? The function passed as the
// handler is invoked.
// What does that function do? It adds a "mouseup" handler.
// Which variable is referenced? "mouseup_vert".
// What is the current value of "mouseup_vert"? The new function, since we
// overwrote the reference to the original.
精彩评论