首页 > 试题广场 >

以下代码执行后,输出结果为()

[单选题]
以下代码执行后,输出结果为() 
let x = 10;
let foo = () => {
    console.log(x);
    let x = 20;
    x++;
}
foo();



  • 抛出ReferenceError
  • 10
  • 20
  • 21
一楼的回答说:”let块级作用域,所以不会去访问外部的x“
是错误的,这题的本质是暂时死区的问题
如图,我单单是去掉了在function中let的定义
这里边的console.log的结果是1,证明了是可以访问function之前定义的变量的,
而之所以会产生reference error是因为暂时死区的问题(temperal dead zone),我为此查了下红宝书,
就是说虽然let语句不像var语句会产生hoisting(变量提升),JavaScript引擎也会意识到在后边的let定义,只是不支持在let声明语句之前引用该变量而已。所以,只要在同一个block中,let是在后边定义的,就不能在之前引用该变量。与此同时,也不能再去取嵌套外层的值了(x=1)

发表于 2020-02-21 11:05:35 回复(7)
编辑于 2019-10-07 21:33:41 回复(1)
let不存在变量提升,所以没有事先声明。 let块级作用域,所以不会去访问外部的x。 既不会访问外部,又没有事先声明,输出x便会报错。
发表于 2019-09-21 02:06:26 回复(2)

实际上 let 也是存在变量提升的

let x = 10;
let foo = () => {
  // 这里访问 x 就会在当前作用域内找 x
  // 如果没有下面的 let x = 20
  // 当前作用域就找不到,然后就会继续找外层变量,最后输出 10
  // 但是下面有声明,声明会提升到当前代码块最前面
  // 这个时候 x 还没有初始化,存在暂存死区中,访问就会抛出 ReferenceError
  console.log(x);
  let x = 20;
  x++;
};
foo();

如果把里面的 let 换成 var 就不会报错,显示 undefined

就是因为 let 是在编译时才会初始化,var 在声明时就会初始化

发表于 2020-11-25 18:30:54 回复(7)
 let x = 10;
 let foo = () => {
  console.log(x);
  let x = 20;
  x++;
 }
 foo();

由于hoisting2~6会被js解释器解释为:

 let foo = () => {
   let x;
   console.log(x); //throws ReferenceError
   x = 20;
   x++;
 }

注意let不同于var:
1. var变量作用域为global或function scope,let可以在更小的范围内如block scope(如{ }括号内、for循环内);
2. var变量声明后会被隐式赋值undefined,而let变量声明后不会被初始化,直到显式的赋值表达式才会被初始化。

refs:

编辑于 2018-12-21 19:49:26 回复(9)
  let :1.不存在变量提升
          2.暂时性死区,使用let命令声明变量之前,该变量都是不可用的
          3.不允许重复声明,不允许在相同作用域内,重复声明同一个变量
发表于 2019-11-26 16:23:19 回复(0)
我认为1楼的说法不太对,有些片面。let和var其实是有提升的
当程序的控制流程在新的作用域(module, function或block作用域)进行实例化时,在此作用域中的用let/const声明的变量会先在作用域中被创建出来,但因此时还未进行词法绑定,也就是对声明语句进行求值运算,所以是不能被访问的,访问就会抛出错误。所以在这运行流程一进入作用域创建变量,到变量开始可被访问之间的一段时间,就称之为TDZ(暂时死区)。
简单来说,let/const在提升后并不会被默认赋值Undefined。
在题目的函数中,let x这个变量其实在这个作用域中已经被创建出来了,只是没有进行词法绑定,没有被赋值Undefined,因此已经创建了也就不会再去全局作用域中找x了
编辑于 2020-03-07 15:16:55 回复(0)

let 的暂时性死去

发表于 2019-09-05 08:51:09 回复(1)

【摘自JavaScript高级程序设计】
let与var的另一个重要的区别,就是let声明的变量不会在作用域中被提升。

// name会被提升
console.log(name); // undefined
var name = 'Matt';

// age不会被提升
console.log(age); // ReferenceError:age没有定义
let age = 26;

在解析代码时,JavaScript引擎也会注意出现在块后面的let声明,只不过在此之前不能以任何方式来引用未声明的变量。在let声明之前的执行瞬间被称为“暂时性死区”(temporal dead zone),在此阶段引用任何后面才声明的变量都会抛出ReferenceError。

发表于 2020-09-26 22:34:20 回复(0)
这道题有一个关键是let存不存在提升
let 不是因为块级作用域无法访问外面的x
而是因为内部的let实际上出现了提升(导致覆盖) 提升+暂时死区导致的报错
可能大家看到觉得不对啊 我一直看的是let不存在提升 和这道题类似的一个例子是
let a = 1 { a = 2  let a }
这个一样会报错Reference Error 变量不能在初始化之前被访问 
实际上 let声明的变量的声明阶段实际上是被提升的
更多关于let详细的信息大家可以看这篇专栏 来自知乎的方应航老师https://zhuanlan.zhihu.com/p/28140450
发表于 2020-03-22 13:14:39 回复(1)

考点:let的暂时性死区

暂时性死区:ES6 明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。

凡是在声明之前就使用这些变量,就会报错。

暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了(类似变量提升),但是不可获取(与变量提升的区别)。

只有等到声明变量的那一行代码出现,才可以获取和使用该变量。

举例说明:


if (true) {  //只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,获取会报错
    
    // 暂时性死区开始
    tmp = 'abc'; // ReferenceError

    console.log(tmp); // ReferenceError

    let tmp; // 暂时性死区结束      //只有等到声明变量的代码出现,才可以获取和使用该变量

    console.log(tmp); // undefined

    tmp = 123;

    console.log(tmp); // 123

}


编辑于 2022-01-04 12:12:33 回复(0)
let的暂时性死区问题,let在块级作用域内系统会意识到后面定义的let,直接锁定后面定义的let,而let没有变量提升,不允许在声明以前使用。
发表于 2021-09-14 08:13:00 回复(0)

JS 和其他语言一样,都要经历编译和执行阶段。正是在这个短暂的编译阶段里,JS 引擎会搜集所有的变量声明,并且提前让声明生效。所以其实let也有提升,使用es6的参数初始化,参数的声明都提升了,会提升的块级作用域顶部,但是提升了却没有初始化,但是var变量提升会初始化为undefined,所以还可以使用,但是let没有初始化,所以在【提前的声明】到【声明初始化】的地方就是暂时性死区,也就是不能在这区间使用这个提升的但没有初始化let变量

编辑于 2021-06-20 13:26:01 回复(0)
其实就是ECMA6的语法变得严格了(let是属于ECMA6),不允许变量在声明之前使用,除此之外还有let是块级作用域的,所以引用不到大括号外面的声明
编辑于 2020-11-13 14:22:35 回复(0)
函数和var都可变量提升,且函数的优先级更高,但是let不可以变量提升,同一个块中,有一个let定义就不会去找外部的,但是由于let是在后面定义的,所以也获取不到,最后报错了
发表于 2020-04-30 15:57:25 回复(0)
注意:let定义的变量其实也会变量提升,但不会赋值undefined。
let x = 10;
let foo = () => {
    console.log(x); 
    x++;
}
foo();
以上代码正常输出10毫无疑问。

--------
如果你在使用x之前手动加上let x; 那么会输出undefined。这说明正常情况下,let的变量也是未定义的。
let x = 10;
let foo = () => {
    let x;
    console.log(x);
    x++;
}
foo();

---------
这种情况,内部实际上let的变量也被提升了,从而覆盖了前面的全局变量。但是js中提升的let变量不能被访问,因此报错
let x = 10;
let foo = () => {
    console.log(x);
    let x = 20;
    x++;
}
foo();
 

发表于 2022-10-15 16:42:34 回复(0)
let会造成 变量提升(Hoisting) ,但是和var的提升不太一样,由于 “暂时性死区”(temporal dead zone) 的缘故,是不能被使用。
暂时性死区 :在let声明之前的执行瞬间叫做暂时性死区,在此阶段引用任何后面才声明的变量都会抛出 ReferenceError(引用错误)
发表于 2022-09-26 11:08:32 回复(0)
ES6 明确规定,如果区块中存在letconst命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。
发表于 2022-01-21 10:54:54 回复(0)
Let暂时性死区,由于在块级作用域fun内定义了let x,因此块级作用域内的所有x被默认锁死为这个后定义的let x,而在定义x之前提前调用了x(console.log(x))因此会产生报错(自己的理解)
发表于 2021-09-11 11:09:00 回复(0)
let声明提升,初始化不提升
发表于 2021-02-05 11:11:05 回复(0)