我很好奇为什么会这样:
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
仍然存在?它不是一个闭包,似乎没有任何东西似乎从外部引用这个变量,所以它不应该被垃圾收集破坏吗?
答案 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”变量的值。