首页 > 其他分享 >let、const、var、function所谓的”变量提升“、暂时性死区到底是什么

let、const、var、function所谓的”变量提升“、暂时性死区到底是什么

时间:2024-02-23 09:57:00浏览次数:22  
标签:function 初始化 const 变量 let 提升 var 暂时性

今天看了大佬一个文章我用了两个月的时间才理解 let - 知乎 (zhihu.com),文章中其实说得很清楚,还有大佬解决这个问题的整个心路历程。我这里做一个总结记录,专注于“变量提升”、暂时性死区这两个点做一个讨论。

现象

讨论下面这两段代码,我们都知道这段代码在控制台会打印undefined

console.log(x); // undefined
var x = 1

而下面这段代码,在控制台打印是会报错的,报什么错先不用在意

console.log(x); // Uncaught ReferenceError: x is not defined

分析其原因的时候,很多人会说因为v8在进行预解析的时候进行了“变量提升”,var x被提升到了最前面,所以第一段代码没有报错,而是打印了undefined。我们暂时认可这种说法,因为目前还能解释我们看到的现象。


接下来讨论下面这两段代码:

console.log(x); // Uncaught ReferenceError: Cannot access 'x' before initialization
let x = 1
console.log(x); // Uncaught ReferenceError: x is not defined

这个时候问题就来了,let存在的时候,到底有没有进行“变量提升”呢?

  • 如果没有进行变量提升,那么上面两段代码应该都报一样x is not defined的错误才对;
  • 如果进行了“变量提升”,那么为什么使用let声明的变量不会与var一样,打印undefined?这时我们可能会想到,这是由于暂时性死区的存在,是它限制了我们不能在let声明之前使用let定义的变量。

这样看,第二种说法可以自圆其说,也是大多数人认为的,但是它不够深入。本文开头提到的知乎大佬的文章中说他咨询了TC39成员,得到的回复是let hoisting不是一个正式词汇,也就是说我们常说的“变量提升”并不是一种确定的行为,而是对行为的一种归纳解释。那么js创建变量时真正的行为是什么呢?

从“提升”角度看解析js时的变量创建过程

在v8执行js代码之前,会对代码进行解析,此时可能会对变量进行三种操作:「创建create、初始化initialize 和赋值assign」。而对于不同的变量声明方式来说:

  • let、const:
    「创建」过程被提升(或者说执行)了。
  • var:
    「创建」和「初始化」都被提升(或者说执行)了。
  • function:
    「创建」「初始化」和「赋值」都被提升(或者说执行)了。

所以总结来说,任何变量声明,都存在提升(或者说预先执行),只不过对于不同的声明方式,提升(或者说预先执行)的部分不同。

而暂时性死区(TDZ),在这个Gist hoisting-vs-tdz.md · GitHub中也说得很明确,结合「创建create、初始化initialize 和赋值assign」三种操作来说,暂时性死区就是在进入作用域之后(也就是「创建」之后),直到let x这个变量声明语句所代表的「初始化」过程中的这段区域。此时由于变量未初始化,所以使用时会抛出Uncaught ReferenceError: Cannot access 'x' before initialization错误。

标签:function,初始化,const,变量,let,提升,var,暂时性
From: https://www.cnblogs.com/CatCatcher/p/18027856

相关文章

  • Machine Learning - The Sigmoid Function
    CalculateNodeOutput.TaskYouaregiventhevaluesforw1,w2,b,x1andx2andyoumustcomputetheoutputforthenode.Usethesigmoidastheactivationfunction.InputFormatw1,w2,b,x1andx2ononelineseparatedbyspacesOutputFormatFloatrounded......
  • 【Azure Function】示例运行 python durable function(model V2)
    问题描述参考官方文档(使用Python创建你的第一个持久函数:https://learn.microsoft.com/zh-cn/azure/azure-functions/durable/quickstart-python-vscode),部署后,却出现“Failedtoloadfunction”错误。在结合以上参考文档后,可以通过如下的步骤创建并运行PythonDurableFu......
  • 使用delete和Vue.delete删除数组元素的区别
    JavaScript中的delete运算符可以删除对象的属性,但是它不适用于数组。如果你试图使用delete运算符删除数组中的元素,你会发现该元素的值变为undefined,而数组的长度并没有改变。Vue.js提供了一个名为Vue.delete的方法,它可以帮助我们在删除数组元素时触发响应式更新。与原生JavaScrip......
  • C++ constexpr
    C++constexpr比如我有一个函数,返回10intget10(){return10;}我想拿去初始化数组大小intarraynum[get10()];编译器会报错,因为会说只能用常量去初始化,所以我们可以用constexpr,把函数改成常量表达式,这样编译器在编译阶段就知道了常量。再比如一个可变参函数模板,我想......
  • CompletableFuture异步编程详解
    Future介绍先来回顾下Future,Future是JDK1.5中添加的接口,主要功能为:获取并发的任务完成后的执行结果;能够取消并发执行中的任务;判断并发任务是否执行完成;但Future也有着非常明显的缺点:阻塞:调用get()方法会一直阻塞,直到等待直到计算完成;异常处理:Future没有提供任何异常处理的方......
  • const、static使用
    关键字使用1.constconst关键字是一个修饰符,所谓“修饰符”,就是在编译器进行编译的过程中,给编译器一些“要求”或“提示”,但修饰符本身,并不产生任何实际代码。就const修饰符而言,它用来告诉编译器,被修饰的这些东西,具有“只读”的特点。在编译的过程中,一旦我们的代码试图去改变......
  • type ColumnTypes = Exclude<EditableTableProps["columns"], undefined>; 这是什么意
    在TypeScript中,Exclude<T,U>是一个内置的类型操作符,它的作用是从联合类型T中排除那些与类型U相匹配的类型。这里的EditableTableProps["columns"]表示从EditableTableProps这个接口或类型中提取columns属性的类型。假设EditableTableProps定义如下:interfaceEdit......
  • SpringBoot应用“No primary or single unique constructor found for interface java
    Bug复现今天在写SpringBoot应用时,写一个后端生成图形验证码的业务时,需要用到session保存后端生成的图形验证码的Base64编码,然后前端通过session来显示图形验证码。代码里用到了servlet里的HttpSession类,于是idea自动导入了javax.servlet包里的HttpSession。业务代码如下:packag......
  • 一文搞懂Flink Window机制 Windows和 Function 和 Process组合处理事件
    一文搞懂FlinkWindow机制和Function和Process组合处理事件Windows是处理无线数据流的核心,它将流分割成有限大小的桶(buckets),并在其上执行各种计算。Windows是处理无线数据流的核心,它将流分割成有限大小的桶(buckets),并在其上执行各种计算。窗口化的Flink程......
  • Flink 增量窗口聚合函数 ReduceFunction(归约函数)和AggregateFunction(聚合函数)
    Flink增量窗口聚合函数定义了窗口分配器,只是知道了数据属于哪个窗口,可以将数据收集起来了;至于收集起来到底要做什么,其实还完全没有头绪。所以在窗口分配器之后,必须再接上一个定义窗口如何进行计算的操作,这就是所谓的“窗口函数”(windowfunctions)。经窗口分配器处理之后,数据可......