【问题标题】:Javascript Execution Context, Counter-Intuitive Scope Chain inside Mouse HandlersJavascript 执行上下文,鼠标处理程序内的反直觉范围链
【发布时间】:2011-06-26 02:20:24
【问题描述】:

这是一个有趣的范围链案例,在很多文档中都没有解释,我觉得很难理解。如果有人能花时间阅读下面注释良好的代码并解释变量是如何得到解决的,那就太好了

我在一个文档上有两个矩形 (DIV)。我在两者上以及在我注册 mouseup 的 mousedown 侦听器中为 mousedown 注册事件侦听器。 mouseup 的监听器中发生了奇怪的事情。

通过使用不同的参数值两次调用 testfunc 来创建两个执行上下文:

window.onload = function() {
     test_func("horizontal"); // First Execution context
     test_func("vertical");  // Second Execution Context
}

在第一个矩形(水平)的 mouseup 侦听器中,正在使用第二个执行上下文(垂直),这是反直觉的:

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_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);
    }            
}

【问题讨论】:

    标签: javascript scope closures


    【解决方案1】:

    这是因为引用函数的变量没有用var 声明,所以它们是全局的。

    它们将被第二个调用覆盖,该调用在 X 附近关闭,值为 9


    编辑: 这就是正在发生的事情。为简单起见,我将所有变量都放在同一个范围内。

       // "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'
    

    ...或者让代码更具体一点:

      // 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.
    

    【讨论】:

    • 没错。那些“mouseup_foo”变量都是全局的。它们必须用var 关键字声明!!此外,从事件处理程序内部设置事件处理程序无论如何都会是一个大问题。
    • 如果它是全局的,那么 X 将在 mousedown_horiz 中设置为 11,这是我应该在 mouseup_horiz 中看到的值,这不是我所看到的,因此是我的问题
    • @Raks 符号“mouseup_vert”、“mousedown_vert”、“mouseup_horiz”和“mousedown_horiz”是全局的。毫无疑问。
    • @Raks:它不显示更新值的原因是您引用该函数实例它被覆盖之前下一个电话。 mouseup_vert/_horiz 函数在 mousedown 事件发生之前不会被引用,因此它们会获取最新版本的全局变量,该变量现在引用第二个 test_func 调用中的函数。
    • ...换句话说,您会立即引用存储在mousedown_horiz/_vert 中的函数,因此在它们有机会被覆盖之前,它们是安全的。由于您对存储在 mouseup_vert/_horiz 中的函数的引用被延迟,因此它们有可能在被引用之前被覆盖。
    猜你喜欢
    • 2012-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-23
    • 1970-01-01
    相关资源
    最近更新 更多