用let或const声明variables是不是在ES6中悬挂的?

我一直在玩ES6一段时间,我注意到,虽然用var声明的variables是如预期的那样悬挂着…

 console.log(typeof name); // undefined var name = "John"; 

…使用letconst声明的variables在提升时似乎有一些问题:

 console.log(typeof name); // ReferenceError let name = "John"; 

 console.log(typeof name); // ReferenceError const name = "John"; 

这是否意味着使用letconst声明的variables不会被挂起? 这里究竟发生了什么? letconst在这个问题上有什么区别吗?

@thefourtheye是正确的说这些variables不能被声明之前被访问 。 但是,比这更复杂一点。

letconst声明variables是不是悬挂的? 这里究竟发生了什么?

所有的声明varletconstfunctionfunction*class都是在JavaScript 中“悬挂”的。 这意味着如果名称在范围内声明,那么在该范围内,标识符将始终引用该特定variables:

 x = "global"; // function scope: (function() { x; // not "global" var/let/… x; }()); // block scope (not for `var`s): { x; // not "global" let/const/… x; } 

对于function和区域范围1都是如此。

var / function / function*声明和let / const / class声明之间的区别是初始化
当在范围顶部创build绑定时,前者被初始化为undefined或(生成器)函数。 词法声明的variables保持未初始化 。 这意味着当您尝试访问它时引发ReferenceErrorexception。 它只会在let / const / class语句被评估时被初始化,所有在before(above)之前被称为时间死区

 x = y = "global"; (function() { x; // undefined y; // Reference error: y is not defined var x = "local"; let y = "local"; }()); 

注意, let y; 语句使用undefined初始化variables,如let y = undefined; 将有。

时间死区不是一个句法位置,而是variables(范围)创build和初始化之间的时间 。 只要代码没有执行(例如函数体或简单的死代码),在声明之上的代码中引用variables并不是错误的,如果在初始化之前访问variables,则会引发exception,即使访问代码在声明之下(例如,在一个被称为过早的提升函数声明中)。

letconst在这个问题上有什么区别吗?

不,他们的工作与吊装相同。 它们之间的唯一区别是const ant必须是,并且只能在声明的初始化部分( const one = 1;const one;而后来的重新分配如one = 2是无效的)分配。

1:当然, var声明仍然只能在函数级别上工作

引用ECMAScript 6(ECMAScript 2015)规范的letconst声明部分,

当它们包含词法环境被实例化时,这些variables被创build,但是在评估variables的LexicalBinding之前,不能以任何方式被访问

所以,为了回答你的问题,是的, letconst hoist,但是在实际声明在运行时被评估之前,你不能访问它们。

ES6引入了Let block level scopingvariablesblock level scopingvariables。 在ES5之前,我们没有block level scoping ,所以在块内声明的variables总是被hoisted到函数级的范围。

基本上, Scope是指你的程序中的variables是可见的,它决定了你允许使用你声明的variables。 在ES5我们有global scope,function scope and try/catch scope ,使用ES6我们也得到了使用let的块级作用域。

  • 当你用var关键字定义一个variables的时候,从定义的那一刻起就知道整个函数。
  • 当你用let语句定义一个variables时,它只能在已经定义的块中知道。

      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"]); 

如果你运行代码,你可以看到variablesj只在loop被知道,而不是在前后。 然而,我们的variablesi从它被定义的那一刻起就被称为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循环总是打印最后一个值, let创build一个新的范围并绑定新的值打印我们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 ,它总是会引用该objectobject本身可以被改变(如果它是可变的)。 如果你喜欢有一个不可变的object ,你可以使用Object.freeze([])