Javascript ES6 中是否未提升使用 let 或 const 声明的变量?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/31219420/
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
Are variables declared with let or const not hoisted in ES6?
提问by Lubo? Turek
I have been playing with ES6 for a while and I noticed that while variables declared with var
are hoisted as expected...
我一直在玩 ES6 一段时间,我注意到虽然声明的变量var
按预期提升......
console.log(typeof name); // undefined
var name = "John";
...variables declared with let
or const
seem to have some problems with hoisting:
...声明的变量let
或const
似乎在提升方面存在一些问题:
console.log(typeof name); // ReferenceError
let name = "John";
and
和
console.log(typeof name); // ReferenceError
const name = "John";
Does this mean that variables declared with let
or const
are not hoisted? What is really going on here? Is there any difference between let
and const
in this matter?
这是否意味着使用let
或未const
提升声明的变量?这里到底发生了什么?在这件事上let
和之间有什么区别const
吗?
回答by Bergi
@thefourtheye is correct in saying that these variables cannot be accessedbefore they are declared. However, it's a bit more complicated than that.
@thefourtheye 说这些变量在声明之前无法访问是正确的。然而,它比那要复杂一些。
Are variables declared with
let
orconst
not hoisted? What is really going on here?
与声明的变量
let
或const
不悬挂?这里到底发生了什么?
All declarations(var
, let
, const
, function
, function*
, class
) are "hoisted"in JavaScript. This means that if a name is declared in a scope, in that scope the identifier will always reference that particular variable:
所有声明(var
, let
, const
, function
, function*
, class
)在 JavaScript 中都被“提升”了。这意味着如果在一个范围内声明了一个名称,那么在该范围内,标识符将始终引用该特定变量:
x = "global";
// function scope:
(function() {
x; // not "global"
var/let/… x;
}());
// block scope (not for `var`s):
{
x; // not "global"
let/const/… x;
}
This is true both for function and block scopes1.
对于函数作用域和块作用域1都是如此。
The difference between var
/function
/function*
declarations and let
/const
/class
declarations is the initialisation.
The former are initialised with undefined
or the (generator) function right when the binding is created at the top of the scope. The lexically declared variables however stay uninitialised. This means that a ReferenceError
exception is thrown when you try to access it. It will only get initialised when the let
/const
/class
statement is evaluated, everything before (above) that is called the temporal dead zone.
之间的差var
/ function
/function*
声明和let
/ const
/class
声明是初始化。当在作用域顶部创建绑定时,
前者使用undefined
或(生成器)函数进行初始化。然而,词法声明的变量保持未初始化。这意味着ReferenceError
当您尝试访问它时会抛出异常。它只会得到当初始化let
/ const
/class
这就是所谓的(上述)之前声明进行评估,一切时间盲区。
x = y = "global";
(function() {
x; // undefined
y; // Reference error: y is not defined
var x = "local";
let y = "local";
}());
Notice that a let y;
statement initialises the variable with undefined
like let y = undefined;
would have.
请注意,let y;
语句会使用undefined
likelet y = undefined;
来初始化变量。
The temporaldead zone is not a syntactic location, but rather the timebetween the variable (scope) creation and the initialisation. It's not an error to reference the variable in code above the declaration as long as that code is not executed (e.g. a function body or simply dead code), and it will throw an exception if you access the variable before the initialisation even if the accessing code is below the declaration (e.g. in a hoisted function declaration that is called too early).
该时间盲区不是语法的位置,而是时间的变量(范围)的创建和初始化之间。只要不执行该代码(例如函数体或简单的死代码),在声明上方的代码中引用变量就不是错误,并且如果您在初始化之前访问该变量,即使访问代码位于声明下方(例如,在过早调用的提升函数声明中)。
Is there any difference between
let
andconst
in this matter?
在这件事上
let
和之间有什么区别const
吗?
No, they work the same as far as hoisting is regarded. The only difference between them is that a const
ant must be and can only be assigned in the initialiser part of the declaration (const one = 1;
, both const one;
and later reassignments like one = 2
are invalid).
不,就提升而言,它们的工作原理相同。它们之间的唯一区别是const
蚂蚁必须并且只能在声明的初始化部分分配(const one = 1;
,两者const one;
和以后的重新分配one = 2
都是无效的)。
1: var
declarations are still working only on the function level, of course
1:当然,var
声明仍然只在函数级别起作用
回答by thefourtheye
Quoting ECMAScript 6 (ECMAScript 2015) specification's, let
and const
declarationssection,
引用 ECMAScript 6 (ECMAScript 2015) 规范let
和const
声明部分,
The variables are created when their containing Lexical Environment is instantiated but may not be accessed in any way until the variable's LexicalBinding is evaluated.
变量在其包含的 Lexical Environment 被实例化时创建,但在评估变量的 LexicalBinding 之前不能以任何方式访问。
So, to answer your question, yes, let
and const
hoist but you cannot access them before the actual declaration is evaluated at runtime.
因此,要回答您的问题,是的,let
并且const
提升但在运行时评估实际声明之前您无法访问它们。
回答by Thalaivar
ES6
introduces Let
variables which comes up with block level scoping
. Until ES5
we did not have block level scoping
, so the variables which are declared inside a block are always hoisted
to function level scoping.
ES6
引入Let
随block level scoping
. 直到ES5
我们没有block level scoping
,所以在块内声明的变量始终hoisted
是函数级别的范围。
Basically Scope
refers to where in your program your variables are visible, which determines where you are allowed to use variables you have declared. In ES5
we have global scope,function scope and try/catch scope
, with ES6
we also get the block level scoping by using Let.
基本上Scope
是指您的变量在程序中的可见位置,这决定了您可以在何处使用已声明的变量。在ES5
我们有global scope,function scope and try/catch scope
, withES6
我们还通过使用 Let 获得块级范围。
- When you define a variable with
var
keyword, it's known the entire function from the moment it's defined. When you define a variable with
let
statement it's only known in the block it's defined.function doSomething(arr){ //i is known here but undefined //j is not known here console.log(i); console.log(j); for(var i=0; i<arr.length; i++){ //i is known here } //i is known here //j is not known here console.log(i); console.log(j); for(let j=0; j<arr.length; j++){ //j is known here } //i is known here //j is not known here console.log(i); console.log(j); } doSomething(["Thalaivar", "Vinoth", "Kabali", "Dinesh"]);
- 当您使用
var
关键字定义变量时,从定义它的那一刻起就知道整个函数。 当你用
let
语句定义一个变量时,它只在它定义的块中是已知的。function doSomething(arr){ //i is known here but undefined //j is not known here console.log(i); console.log(j); for(var i=0; i<arr.length; i++){ //i is known here } //i is known here //j is not known here console.log(i); console.log(j); for(let j=0; j<arr.length; j++){ //j is known here } //i is known here //j is not known here console.log(i); console.log(j); } doSomething(["Thalaivar", "Vinoth", "Kabali", "Dinesh"]);
If you run the code, you could see the variable j
is only known in the loop
and not before and after. Yet, our variable i
is known in the entire function
from the moment it is defined onward.
如果你运行代码,你可以看到变量j
只在 the 中,loop
而不是 before 和 after 中。然而,我们的变量从定义的那一刻起i
就是已知的entire function
。
There is another great advantage using let as it creates a new lexical environment and also binds fresh value rather than keeping an old reference.
使用 let 还有一个很大的优势,因为它创建了一个新的词法环境并且绑定了新的值而不是保留一个旧的引用。
for(var i=1; i<6; i++){
setTimeout(function(){
console.log(i);
},1000)
}
for(let i=1; i<6; i++){
setTimeout(function(){
console.log(i);
},1000)
}
The first for
loop always print the lastvalue, with let
it creates a new scope and bind fresh values printing us 1, 2, 3, 4, 5
.
第一个for
循环总是打印最后一个值,let
它创建一个新的作用域并绑定打印 us 的新值1, 2, 3, 4, 5
。
Coming to constants
, it work basically like let
, the only difference is their value can't be changed. In constants mutation is allowed but reassignment is not allowed.
来到constants
,它的工作原理与let
,唯一的区别是它们的值不能改变。在常量中允许突变,但不允许重新分配。
const foo = {};
foo.bar = 42;
console.log(foo.bar); //works
const name = []
name.push("Vinoth");
console.log(name); //works
const age = 100;
age = 20; //Throws Uncaught TypeError: Assignment to constant variable.
console.log(age);
If a constant refers to an object
, it will always refer to the object
but the object
itself can be changed (if it is mutable). If you like to have an immutable object
, you could use Object.freeze([])
如果常量引用 an object
,它将始终引用 theobject
但它object
本身可以更改(如果它是可变的)。如果你喜欢不可变的object
,你可以使用Object.freeze([])
回答by YourAboutMeIsBlank
From MDN web docs:
In ECMAScript 2015, let
and const
are hoisted but not initialized. Referencing the variable in the block before the variable declaration results in a ReferenceError
because the variable is in a "temporal dead zone" from the start of the block until the declaration is processed.
在2015年的ECMAScript,let
并const
高挂,但没有初始化。在变量声明之前引用块中的变量会导致 a,ReferenceError
因为从块的开始直到处理声明,变量都处于“时间死区”中。
console.log(x); // ReferenceError
let x = 3;