Javascript 函数作用域和提升
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7506844/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Javascript function scoping and hoisting
提问by dev.e.loper
I just read a great article about JavaScript Scoping and Hoisting by Ben Cherryin which he gives the following example:
我刚刚阅读了Ben Cherry撰写的一篇关于JavaScript 范围和提升的很棒的文章,他在其中给出了以下示例:
var a = 1;
function b() {
a = 10;
return;
function a() {}
}
b();
alert(a);
Using the code above, the browser will alert "1".
使用上面的代码,浏览器会提示“1”。
I'm still unsure why it returns "1". Some of the things he says come to mind like: All the function declarations are hoisted to the top. You can scope a variable using function. Still doesn't click for me.
我仍然不确定为什么它返回“1”。他说的一些事情浮现在脑海中:所有的函数声明都被提升到顶部。您可以使用函数作用域变量。仍然没有为我点击。
回答by Peter Olson
Function hoisting means that functions are moved to the top of their scope. That is,
函数提升意味着函数被移动到其作用域的顶部。那是,
function b() {
a = 10;
return;
function a() {}
}
will be rewritten by the interpeter to this
将由 interpeter 重写为此
function b() {
function a() {}
a = 10;
return;
}
Weird, eh?
很奇怪吧?
Also, in this instance,
此外,在这种情况下,
function a() {}
behaved the same as
表现与
var a = function () {};
So, in essence, this is what the code is doing:
所以,本质上,这就是代码所做的:
var a = 1; //defines "a" in global scope
function b() {
var a = function () {}; //defines "a" in local scope
a = 10; //overwrites local variable "a"
return;
}
b();
alert(a); //alerts global variable "a"
回答by kemiller2002
What you have to remember is that it parses the whole function and resolves all the variables declarations before executing it. So....
您必须记住的是,它会在执行之前解析整个函数并解析所有变量声明。所以....
function a() {}
really becomes
真的变成
var a = function () {}
var a
forces it into a local scope, and variable scope is through the entire function, so the global a variable is still 1 because you have declared a into a local scope by making it a function.
var a
强制它进入局部作用域,而变量作用域是贯穿整个函数的,所以全局 a 变量仍然是 1,因为你已经通过将 a 声明为一个函数而进入局部作用域。
回答by Digital Plane
The function a
is hoisted inside function b
:
该函数a
在函数内部被提升b
:
var a = 1;
function b() {
function a() {}
a = 10;
return;
}
b();
alert(a);
which is almost like using var
:
这几乎就像使用var
:
var a = 1;
function b() {
var a = function () {};
a = 10;
return;
}
b();
alert(a);
The function is declared locally, and setting a
only happens in the local scope, not the global var.
该函数是在本地声明的,并且设置a
只发生在本地范围内,而不是全局变量。
回答by Jhankar Mahbub
- function declaration
function a(){}
is hoisted first and it behaves likevar a = function () {};
, hence in local scopea
is created. - If you have two variable with same name (one in global another in local), local variable always get precedence over global variable.
- When you set
a=10
, you are setting the local variablea
, not the global one.
- 函数声明
function a(){}
首先被提升,它的行为类似于var a = function () {};
,因此在本地范围内a
被创建。 - 如果你有两个同名的变量(一个在全局另一个在本地),局部变量总是优先于全局变量。
- 设置时
a=10
,您设置的是局部变量a
,而不是全局变量。
Hence, the value of global variable remain same and you get, alerted 1
因此,全局变量的值保持不变,您会收到警报 1
回答by SLaks
function a() { }
is a function statement, which creates an a
variable local to the b
function.
Variables are created when a function is parsed, regardless of whether the var
or function statement gets executed.
function a() { }
是一个函数语句,它创建一个函数a
局部变量b
。
解析函数时会创建变量,而不管var
or 函数语句是否被执行。
a = 10
sets this local variable.
a = 10
设置这个局部变量。
回答by xgqfrms
scpope & closure & hoisting (var/function)
scpope & 关闭 & 提升 (var/function)
- scpope : the global var can be access in any place(the whole file scope), local var only can be accessed by the local scope(function/block scope)!
Note: if a local variable not using var keywords in a function, it will become a global variable!- closure : a function inner the other function, which can access local scope(parent function) & global scope, howerver it's vars can't be accessed by others! unless, your return it as return value!
- hoisting : move all declare/undeclare vars/function to the scope top, than assign the value or null!
Note: it just move the declare,not move the value!
- scpope :全局变量可以在任何地方(整个文件范围)访问,局部变量只能被局部范围(函数/块范围)访问!
注意:如果一个局部变量在函数中没有使用 var 关键字,它将成为一个全局变量!- 闭包:另一个函数内部的函数,它可以访问局部作用域(父函数)和全局作用域,但是它的变量不能被其他人访问!除非,您将其作为返回值返回!
- 提升:将所有声明/取消声明的变量/函数移动到作用域顶部,而不是赋值或为空!
注意:它只是移动声明,而不是移动值!
var a = 1;
//"a" is global scope
function b() {
var a = function () {};
//"a" is local scope
var x = 12;
//"x" is local scope
a = 10;
//global variable "a" was overwrited by the local variable "a"
console.log("local a =" + a);
return console.log("local x = " + x);
}
b();
// local a =10
// local x = 12
console.log("global a = " + a);
// global a = 1
console.log("can't access local x = \n");
// can't access local x =
console.log(x);
// ReferenceError: x is not defined
回答by Sagar Munjal
What is the bone of contention in this small snippet of code?
这段代码中的争论焦点是什么?
Case 1:
情况1:
Include function a(){}
definition inside the body of function b
as follows. logs value of a = 1
function a(){}
在下面的正文中包含定义function b
。logs value of a = 1
var a = 1;
function b() {
a = 10;
return;
function a() {}
}
b();
console.log(a); // logs a = 1
Case 2
案例二
Exclude function a(){}
definition inside the body of function b
as follows. logs value of a = 10
排除function a(){}
体内的function b
定义如下。logs value of a = 10
var a = 1;
function b() {
a = 10; // overwrites the value of global 'var a'
return;
}
b();
console.log(a); // logs a = 10
Observation will help you realise that statement console.log(a)
logs the following values.
观察将帮助您意识到该语句console.log(a)
记录以下值。
Case 1 :a = 1
情况 1:a = 1
Case 2 :a = 10
情况 2:a = 10
Posits
位置
var a
has been defined and declared lexically in the global scope.a=10
This statement is reassigning value to 10, it lexically sits inside the function b.
var a
已在全局范围内按词法定义和声明。a=10
该语句将值重新分配给 10,它在词法上位于函数 b 内。
Explanation of both the cases
两种情况的解释
Because of function definition with name property
a is same as the variable a
. The variable a
inside the function body b
becomes a local variable. The previous line implies that the global value of a remains intact and the local value of a is updated to 10.
因为function definition with name property
a 与variable a
. 该variable a
内部function body b
成为一个局部变量。前一行暗示 a 的全局值保持不变,而 a 的局部值更新为 10。
So, what we intend to say is that the code below
所以,我们想说的是下面的代码
var a = 1;
function b() {
a = 10;
return;
function a() {}
}
b();
console.log(a); // logs a = 1
It is interpreted by the JS interpreter as follows.
JS解释器解释如下。
var a = 1;
function b() {
function a() {}
a = 10;
return;
}
b();
console.log(a); // logs a = 1
However, when we remove the function a(){} definition
, the value of 'a'
declared and defined outside the function b, that value gets overwritten and it changes to 10 in case 2. The value gets overwritten because a=10
refers to the global declaration and if it were to be declared locally we must have written var a = 10;
.
然而,当我们删除了function a(){} definition
,该value of 'a'
声明和函数B外定义,该值被覆盖,并在壳体2的值被覆盖,因为更改为10a=10
指的是全局声明,如果它是在本地声明,我们必须有写的var a = 10;
。
var a = 1;
function b() {
var a = 10; // here var a is declared and defined locally because it uses a var keyword.
return;
}
b();
console.log(a); // logs a = 1
We can clarify our doubt further by changing the name property
in function a(){} definition
to some other name than 'a'
我们可以通过将name property
in更改为function a(){} definition
其他名称来进一步澄清我们的疑问'a'
var a = 1;
function b() {
a = 10; // here var a is declared and defined locally because it uses a var keyword.
return;
function foo() {}
}
b();
console.log(a); // logs a = 1
回答by Buzzzzzzz
Hoisting is a concept made for us to make it easier to understand. What actually happens is the declarations are done first with respect to their scopes and the assignments will happen after that(not at the same time).
吊装是一个让我们更容易理解的概念。实际发生的是首先针对其范围进行声明,然后进行分配(不是同时进行)。
When the declarations happen, var a
, then function b
and inside that b
scope, function a
is declared.
当声明发生时,var a
, 然后function b
和在该b
范围内,function a
被声明。
This function a will shadow the variable a coming from the global scope.
这个函数 a 将隐藏来自全局作用域的变量 a。
After the declarations are done, the values assign will start, the global a
will get the value 1
and the a inside function b
will get 10
.
when you do alert(a)
, it will call the actual global scope variable.
This little change to the code will make it more clear
声明完成后,值分配将开始,全局a
将获得值1
,内部function b
将获得10
。当你这样做时alert(a)
,它会调用实际的全局范围变量。代码的这个小改动会让它更清晰
var a = 1;
function b() {
a = 10;
return a;
function a() { }
}
alert(b());
alert(a);
回答by Donato
Suprisingly, none of the answers here mention the relevancy of the Execution Context in the Scope Chain.
令人惊讶的是,这里的答案都没有提到作用域链中执行上下文的相关性。
The JavaScript Engine wraps the currently executing code in an Execution Context. The base execution context is the global Execution Context. Each time a new function is invoked, a new Execution Context is created and put on the Execution Stack. Think of a Stack Frame sitting on an Invocation Stack in other programming languages. Last in first out. Now each Execution Context has its own Variable Environment and Outer Environment in JavaScript.
JavaScript 引擎将当前正在执行的代码包装在一个执行上下文中。基本执行上下文是全局执行上下文。每次调用新函数时,都会创建一个新的执行上下文并将其放入执行堆栈。想想其他编程语言中位于调用堆栈上的堆栈框架。后进先出。现在每个执行上下文在 JavaScript 中都有自己的变量环境和外部环境。
I will use the below example as a demonstration.
我将使用以下示例作为演示。
1) First, we enter the Creation Phase of the global Execution Context. Both the Outer Environment and Variable Environment of the Lexical Environment are created. The Global Object is setup and placed in memory with the special variable 'this' pointing to it. The function a and its code and the variable myVar with an undefined value are placed in memory in the global Variable Environment. it's important to note that function a's code is not executed. It is just placed in memory with function a.
1) 首先,我们进入全局执行上下文的创建阶段。创建词法环境的外部环境和变量环境。全局对象被设置并放置在内存中,特殊变量“this”指向它。函数 a 及其代码以及具有未定义值的变量 myVar 被放置在全局变量环境中的内存中。需要注意的是,函数 a 的代码没有被执行。它只是放在内存中,函数a。
2) Second, it is the Execution Phase of the Execution Context. myVar is no longer an undefined value. It is initialized with value of 1, which is stored in the global Variable Environment. The function a is invoked and a new Execution Context is created.
2) 其次是执行上下文的执行阶段。myVar 不再是未定义的值。它以值 1 初始化,该值存储在全局变量环境中。调用函数 a 并创建一个新的执行上下文。
3) In the function a's Execution Context, it goes through the Creation and Execution Phase of its own Execution Context. It has its own Outer Environment and Variable Environment, thus, its own Lexical Environment. The function b and the variable myVar are stored in its Variable Environment. This Variable Environment is distinct from the global Variable Environment. Since the function a sits lexically (physically in code) on the same level as the global Execution Context, its Outer Environment is the global Execution Context. Thus, if the function a was to refer to a variable that is not in its Variable Environment, it will search the Scope Chain and try to find the variable in the Variable Environment of the global Execution Context.
3)在函数a的执行上下文中,它经历了自己的执行上下文的创建和执行阶段。它有自己的外部环境和变量环境,因此,有自己的词法环境。函数 b 和变量 myVar 存储在其变量环境中。这个变量环境不同于全局变量环境。由于函数 a 在词法上(物理上在代码中)与全局执行上下文处于同一级别,因此其外部环境是全局执行上下文。因此,如果函数 a 要引用不在其变量环境中的变量,它将搜索作用域链并尝试在全局执行上下文的变量环境中查找变量。
4) The function b is invoked in function a. A new Execution Context is created. Since it sits lexically in function a, its Outer Environment is a. So when it references myVar, since myVar is not in function b's Variable Environment, it will look in function a's Variable Environment. It finds it there and console.log prints 2. But if the variable was not in function a's Variable Environment, then since function a's Outer Environment is the global Execution Context, then the Scope Chain will continue searching there.
4) 在函数a 中调用函数b。一个新的执行上下文被创建。由于它在词法上位于函数 a 中,因此它的外部环境是 a。所以当它引用 myVar 时,由于 myVar 不在函数 b 的变量环境中,它会在函数 a 的变量环境中查找。它在那里找到它并且 console.log 打印 2。但是如果变量不在函数 a 的变量环境中,那么由于函数 a 的外部环境是全局执行上下文,那么作用域链将继续在那里搜索。
5) After function b and a are finished execution, they are popped from the Execution Stack. The single-threaded JavaScript Engine continues execution at the global Execution Context. It invokes the b function. But there is no b function in the global Variable Environment and there is no other Outer Environment to search in the global Execution Context. Thus an exception is raised by the JavaScript Engine.
5) 函数 b 和 a 执行完毕后,从执行栈中弹出。单线程 JavaScript 引擎在全局执行上下文中继续执行。它调用 b 函数。但是全局变量环境中没有 b 函数,全局执行上下文中也没有其他外部环境可以搜索。因此,JavaScript 引擎会引发异常。
function a(){
function b(){
console.log(myVar);
}
var myVar = 2;
b();
}
var myVar = 1;
a();
b();
> 2
> Uncaught ReferenceError: b is not defined
The below example shows the Scope Chain in action. In the function b's Execution Context's Variable Environment, there is no myVar. So it searches its Outer Environment, which is the function a. The function a does not have myVar in its Variable Environment either. So the Engine searches function a's Outer Environment, which is the global Execution Context's Outer Environment and myVar is defined there. Hence, the console.log prints 1.
下面的示例显示了作用域链。在函数b的Execution Context的Variable Environment中,没有myVar。所以它搜索它的外部环境,也就是函数a。函数 a 在其变量环境中也没有 myVar 。所以Engine搜索函数a的Outer Environment,也就是全局执行上下文的Outer Environment,myVar就是在那里定义的。因此,console.log 打印 1。
function a(){
function b(){
console.log(myVar);
}
b();
}
var myVar = 1;
a();
> 1
Regarding Execution Context and the Lexical Environment associated with it, including Outer Environment and Variable Environment, enable the scoping of variables in JavaScript. Even if you invoke the same function multiple times, for each invocation, it will create its own Execution Context. So each Execution Context will have its own copy of the variables in its Variable Environment. There is no sharing of variables.
关于执行上下文和与之相关的词法环境,包括外部环境和变量环境,启用 JavaScript 中变量的范围。即使多次调用同一个函数,对于每次调用,它也会创建自己的执行上下文。因此,每个执行上下文将在其变量环境中拥有自己的变量副本。没有共享变量。
回答by Nam V. Do
From my piece of knowledge, hoisting happens with the variable declaration and function declaration, for example:
根据我的知识,提升发生在变量声明和函数声明中,例如:
a = 7;
var a;
console.log(a)
What happens inside JavaScript's engine:
JavaScript 引擎内部发生了什么:
var a;
a = 7;
console.log(a);
// 7
Or:
或者:
console.log(square(7)); // Output: 49
function square(n) { return n * n; }
It will become:
它会变成:
function square(n) { return n * n; }
console.log(square(7)); // 49
But assignments such as variable assigment, function expression assignment will not be hoisted: For example:
但是变量赋值、函数表达式赋值等赋值不会被提升:例如:
console.log(x);
var x = 7; // undefined
It may become like this:
它可能会变成这样:
var x;
console.log(x); // undefined
x = 7;