我一直在玩ES6一段时间,我注意到虽然用var
声明的变量按预期挂起......
console.log(typeof name); // undefined
var name = "John";
...使用let
或const
声明的变量似乎在提升方面存在一些问题:
console.log(typeof name); // ReferenceError
let name = "John";
和
console.log(typeof name); // ReferenceError
const name = "John";
这是否意味着用let
或const
声明的变量不会被挂起?这是怎么回事?这件事let
和const
之间有什么区别吗?
答案 0 :(得分:290)
@thefourtheye在声明这些变量之前无法访问是正确的。但是,它有点复杂。
是否声明了
let
或const
声明的变量?这里到底发生了什么?
所有声明(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;
}
对于函数和块作用域 1 都是如此。
var
/ function
/ function*
声明与let
/ const
/ class
声明之间的差异是初始化< / strong>即可。
当在作用域顶部创建绑定时,前者使用undefined
或(生成器)函数进行初始化。然而,词汇声明的变量保持未初始化。这意味着当您尝试访问它时会引发ReferenceError
异常。它只会在评估let
/ const
/ class
语句时进行初始化,在(上面)之前的所有内容称为时间死区。
x = y = "global";
(function() {
x; // undefined
y; // Reference error: y is not defined
var x = "local";
let y = "local";
}());
请注意,let y;
语句会使用undefined
之类的let y = undefined;
初始化变量。
temporal 死区不是语法位置,而是变量(范围)创建和初始化之间的 time 。只要不执行该代码(例如函数体或简单的死代码),引用声明上方代码中的变量并不是错误,如果在初始化之前访问变量,即使访问它也会引发异常代码在声明之下(例如,在过早调用的提升函数声明中)。
此问题
let
和const
之间是否存在差异?
不,就提升而言,它们的工作原理相同。它们之间的唯一区别是,const
蚂蚁必须且只能在声明的初始化部分(const one = 1;
,const one;
和之后的one = 2
重新分配中分配无效)。
1:var
声明仍然只在功能级别上工作,当然
答案 1 :(得分:72)
引用ECMAScript 6(ECMAScript 2015)规范&#39; s,let
and const
declarations部分,
变量是在实例化包含词法环境时创建的,但在评估变量的LexicalBinding之前可能无法以任何方式访问 。
所以,回答你的问题,是的,let
和const
提升,但在运行时评估实际声明之前你无法访问它们。
答案 2 :(得分:18)
ES6
介绍Let
提出的block level scoping
变量。在ES5
之前我们没有block level scoping
,所以在块内声明的变量总是hoisted
到函数级别范围。
基本上Scope
指的是程序中变量可见的位置,它决定了您允许使用已声明的变量的位置。在ES5
我们有global scope,function scope and try/catch scope
,ES6
我们也可以使用Let获取块级别范围。
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"]);
如果您运行代码,您可以看到变量j
仅在loop
中已知,而不是之前和之后。然而,我们的变量i
在entire function
中从定义之后就知道了。
使用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)
}
第一个for
循环始终打印 last 值,let
它会创建一个新范围并绑定新值,打印我们1, 2, 3, 4, 5
。
来到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);
如果常量引用object
,它将始终引用object
,但object
本身可以更改(如果它是可变的)。如果您希望拥有不可变object
,则可以使用Object.freeze([])
答案 3 :(得分:1)
在ECMAScript 2015中,let
和const
被吊起但未初始化。在变量声明之前引用该块中的变量会导致ReferenceError
,因为该变量从块的开始一直到声明被处理,都处于“临时死区”。
console.log(x); // ReferenceError
let x = 3;
答案 4 :(得分:1)
在es6中,当我们使用let或const时,必须在使用它们之前声明变量。 例如。 1-
// this will work
u = 10;
var u;
// this will give an error
k = 10;
let k; // ReferenceError: Cannot access 'k' before initialization.
例如2-
// this code works as variable j is declared before it is used.
function doSmth() {
j = 9;
}
let j;
doSmth();
console.log(j); // 9
答案 5 :(得分:1)
在函数或脚本的顶层,将函数声明视为var声明,而不是词汇声明。
在变量声明之前在块中引用变量会导致ReferenceError,因为变量从块的开始一直到声明被处理为止,都处于“临时死区”中。 >
下面的示例清楚地说明了“ let”变量在词法作用域/嵌套词法作用域中的行为。
var a;
console.log(a); //undefined
console.log(b); //undefined
var b;
let x;
console.log(x); //undefined
console.log(y); // Uncaught ReferenceError: y is not defined
let y;
变量“ y”给出了referenceError,这并不意味着它没有被提升。实例化包含环境时创建该变量。但是,由于它处于无法访问的“临时死区”,因此可能无法访问它。
let mylet = 'my value';
(function() {
//let mylet;
console.log(mylet); // "my value"
mylet = 'local value';
})();
let mylet = 'my value';
(function() {
let mylet;
console.log(mylet); // undefined
mylet = 'local value';
})();
在示例3中,函数内部新声明的“ mylet”变量在log语句之前没有初始化程序,因此值为“ undefined”。