简体   繁体   English

JavaScript词汇范围和变量寿命

[英]JavaScript Lexical Scoping and Life of Variable

I was curious why this works: 我很好奇为什么这样做:

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

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

which makes sense, as the variable does not exist outside of the function. 这很有意义,因为变量不在函数外部。 But if I make a function that self executes: 但是,如果我做一个自我执行的功能:

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

console.log(counter); // returns 0

How come the variable counter still exists? 变量counter又如何存在? It's not a closure, there's nothing that seems to be referencing this variable from the outside, so shouldn't it be destroyed by garbage collection? 这不是一个闭包,似乎没有什么可以从外部引用此变量,所以它不应该被垃圾回收破坏吗?

You are creating it as a global as you haven't included var before the variable name. 您正在将其创建为全局变量,因为您没有在变量名称之前包含var

The function in the first example hasn't been invoked so the variable has not been created yet, in the second one it has so that is why you get 0 第一个示例中的函数尚未被调用,因此尚未创建变量,而在第二个示例中,则具有变量,因此您得到0

What your code should be doing is: 您的代码应该做什么:

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

First edit them so that it is instantly clear what's happening (no leaving out var hacks): 首先对其进行编辑,以便立即了解正在发生的事情(不遗漏var hacks):

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

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

And: 和:

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

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

Can you now see what's happening? 您现在可以看到发生了什么吗? The function defines a global variable so of course it's not available until the function is called. 该函数定义了一个全局变量,因此,在调用该函数之前,它当然是不可用的。 window refers to the [object global] in browsers. window是指浏览器中的[object global]

This is the reason you always want to use either global.something OR var something , so that it's very clear to anyone whether you intend to use global or local variable. 这就是为什么您总是想使用global.somethingvar something ,因此对于任何人来说,无论您打算使用全局变量还是局部变量,都非常清楚。 If you used var in the OP, the variable would be local. 如果在OP中使用var ,则该变量将是局部变量。

Since you are not declaring it with "var" it gets assigned to the global scope which is visible out side of the function. 由于您未使用“ var”进行声明,因此将其分配给在函数外部可见的全局范围。 In the first example you are not executing the function so the counter is never defined where as in the second example you invoke the function and counter gets assigned to the global scope 在第一个示例中,您没有执行函数,因此从未定义计数器,而在第二个示例中,您调用了函数,并且将计数器分配给了全局范围

In the first example you haven't called the function and so counter doesn't exist yet (because the code inside the function hasn't executed yet). 在第一个示例中,您尚未调用该函数,因此还不存在counter (因为该函数内的代码尚未执行)。 In the second example, you have defined a function literal and you are self-invoking it. 在第二个示例中,您已经定义了一个函数文字,并且正在自动调用它。 The code inside the function execute and counter is now defined. 现在定义了函数execute和counter的代码。

Furthermore counter is a global variable because you haven't defined it using var and so it is visible to the scope outside the function. 此外, counter是全局变量,因为您尚未使用var定义它,因此它对函数外部的作用域是可见的。 It's the same as doing window.counter = 0 . 与执行window.counter = 0相同。

Now if you had done the following: 现在,如果您已执行以下操作:

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

counter would still be undefined because it is local to the scope of the function. counter仍将是未定义的,因为它在函数范围内是局部的。

So to recap: 总结一下:

  • In the first example counter is undefined because the code hasn't run yet. 在第一个示例中,未定义counter ,因为代码尚未运行。 If you actually call the function, you will get the same behavior as the second example. 如果您实际调用该函数,则将获得与第二个示例相同的行为。
  • In the second example counter is defined and is a global variable (basically the same as window.counter ) and it is defined because the code inside the function was executed when you defined it and self-invoked it. 在第二个示例中,定义了counter ,它是一个全局变量(与window.counter基本相同),它的定义是因为函数内部的代码是在定义并自动调用时执行的。
  • In the third example counter is unknown to the global scope because it is local to the function inside which it was defined (because var was used). 在第三个示例中, counter对于全局作用域是未知的,因为它在定义它的函数内部是局部的(因为使用了var )。

As you know, in JavaScript, if you declare a variable without "var" keyword, it will be added to the global scope(window object). 如您所知,在JavaScript中,如果声明不带“ var”关键字的变量,它将被添加到全局范围(窗口对象)。

But if a variable is declared within a function without using "var" keyword, it won't be added to the global scope(window object) until that particular function is invoked. 但是,如果在函数中声明变量而不使用“ var”关键字,则在调用该特定函数之前,不会将其添加到全局范围(窗口对象)。 In JavaScript, you have to understand about execution context creation. 在JavaScript中,您必须了解执行上下文的创建。

when the complete JS file is interpreted, the the memory is allocated for all the functions and variables(hoisting). 当解释完整的JS文件时,将为所有功能和变量分配内存(提升)。 Please note that all the variables which are declared outside of the functions are added to the global scope(window object). 请注意,所有在函数外部声明的变量都将添加到全局范围(窗口对象)。

Execution phase: 执行阶段:

As JS code execution is synchronous(only one line at a time) and single threaded, an execution stack is created and the "global execution context" is pushed to the execution stack. 由于JS代码执行是同步的(一次只执行一行)并且是单线程的,因此将创建一个执行堆栈,并将“全局执行上下文”推入执行堆栈。 If a function invocation is encountered in the execution, "function execution context" is created for the corresponding function and pushed to the same stack. 如果在执行过程中遇到函数调用,则会为相应的函数创建“函数执行上下文”,并将其压入同一堆栈。

Now during function execution, JS engine parse the code and if it come across a variable, the memory is allocated and if the variable is declared without "var" keyword, it will add this particular variable to the global scope. 现在,在函数执行过程中,JS引擎将解析代码,如果遇到一个变量,则会分配内存,并且如果声明的变量没有使用“ var”关键字,它将将该特定变量添加到全局范围中。 otherwise that particular variable will be part of function scope(local scope). 否则,该特定变量将成为函数作用域(局部作用域)的一部分。

Now let's check your code snippets: 现在,让我们检查一下您的代码段:

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

console.log(counter); console.log(counter); // returns "reference error: can't find variable" //返回“参考错误:找不到变量”

in this example, as the doThis() function is never executed, variable "counter " is not allocated any memory and not part of any scope(global/local). 在此示例中,由于从未执行doThis()函数,因此不会为变量“ counter”分配任何内存,也不是任何范围(全局/局部)的一部分。 hence in the console log, you see a reference error. 因此,在控制台日志中,您会看到参考错误。

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

console.log(counter); console.log(counter); // returns 0 //返回0

As its a self invoking function, "counter" variable will be allocated memory and moved to the global scope(window object). 作为其自调用功能,“计数器”变量将被分配内存并移至全局范围(窗口对象)。 hence you can see the value of the "counter" variable in the console log. 因此,您可以在控制台日志中看到“ counter”变量的值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM