JavaScript词汇范围与变量生命

时间:2011-11-15 15:27:54

标签: javascript function closures scope

我很好奇为什么会这样:

function doThis(){
    counter = 0;
    return counter;
};

console.log(counter); // returns "reference error: can't find variable"

这是有道理的,因为变量不存在于函数之外。但是,如果我创建一个自我执行的函数:

(function doThis(){
    counter = 0;
    return counter;
})();

console.log(counter); // returns 0

为什么变量counter仍然存在?它不是一个闭包,似乎没有任何东西似乎从外部引用这个变量,所以它不应该被垃圾收集破坏吗?

5 个答案:

答案 0 :(得分:6)

您正在将其创建为全局,因为您没有在变量名称之前包含var

第一个示例中的函数尚未被调用,因此尚未创建变量,在第二个示例中,它具有0

的原因

您的代码应该做的是:

function doThis(){
    var counter = 0;
    return counter;
};

答案 1 :(得分:4)

首先编辑它们,以便立即清楚发生了什么(没有遗漏变种黑客):

function doThis(){
    window.counter = 0;
    return counter;
};

console.log(window.counter); // returns undefind

(function doThis(){
    window.counter = 0;
    return counter;
})();

console.log(window.counter); // returns 0

你现在能看到发生了什么吗?该函数定义了一个全局变量,因此在调用该函数之前它不可用。 window指的是浏览器中的[object global]

这就是你总是想要使用global.something OR var something的原因,因此无论你是打算使用全局变量还是本地变量,都非常清楚。如果您在OP中使用var,则该变量将是本地的。

答案 2 :(得分:3)

由于您未使用“var”声明它,因此会将其分配给在函数外部可见的全局范围。在第一个示例中,您没有执行该函数,因此永远不会定义计数器,如第二个示例中所示,您调用函数并将计数器分配给全局范围

答案 3 :(得分:2)

在第一个示例中,您尚未调用该函数,因此counter尚不存在(因为函数内部的代码尚未执行)。在第二个示例中,您已定义了一个函数文字,并且您可以自行调用它。现在定义了函数execute和counter中的代码。

此外counter是一个全局变量,因为您没有使用var定义它,因此它对函数外部的范围可见。这跟window.counter = 0一样。

现在,如果您已完成以下操作:

(function doThis(){
    var counter = 0; //notice the var
    return counter;
})();

counter仍然是未定义的,因为它是函数范围的本地。

所以回顾一下:

  • 在第一个示例中,counter未定义,因为代码尚未运行。如果您实际调用该函数,您将获得与第二个示例相同的行为。
  • 在第二个示例中,定义了counter并且它是一个全局变量(基本上与window.counter相同)并且它被定义,因为函数内部的代码在您定义并自我调用时执行它。
  • 在第三个示例中,counter对于全局范围是未知的,因为它是定义它的函数的本地(因为使用了var)。

答案 4 :(得分:0)

如您所知,在JavaScript中,如果声明一个没有“var”关键字的变量,它将被添加到全局范围(窗口对象)。

但是如果在不使用“var”关键字的情况下在函数内声明变量,则在调用该特定函数之前,不会将其添加到全局范围(窗口对象)。 在JavaScript中,您必须了解执行上下文创建。

当解释完整的JS文件时,将为所有函数和变量(提升)分配内存。 请注意,在函数外部声明的所有变量都将添加到全局范围(窗口对象)。

执行阶段:

由于JS代码执行是同步的(一次只有一行)和单线程,因此创建执行堆栈并将“全局执行上下文”推送到执行堆栈。 如果在执行中遇到函数调用,则会为相应的函数创建“函数执行上下文”并将其推送到同一堆栈。

现在在函数执行期间,JS引擎解析代码,如果遇到变量,则分配内存,如果声明变量没有“var”关键字,则会将此特定变量添加到全局范围。否则该特定变量将成为功能范围(本地范围)的一部分。

现在让我们检查你的代码片段:

function doThis(){
    counter = 0;
    return counter;
};

的console.log(计数器); //返回“引用错误:无法找到变量”

在此示例中,由于doThis()函数从未执行,因此变量“counter”未分配任何内存,也不属于任何范围(全局/本地)。因此,在控制台日志中,您会看到引用错误。

(function doThis(){
    counter = 0;
    return counter;
})();

的console.log(计数器); //返回0

由于它是一个自调用函数,“counter”变量将被分配内存并移动到全局范围(window object)。因此,您可以在控制台日志中看到“counter”变量的值。