深入了解JavaScript中let/var/function的变量提升
作者: 橘皮
前言
在我们的印象中,当提到JavaScript
中的变量提升,我们想到的是“变量和函数的声明在物理层面移动到代码的最前面“。当然这么说不大准确,变量和函数声明在代码里的位置是不会变的,而是在编译阶段被放入内存中。
可是如果我问你:let 到底有没有提升?如果有,var / let / function三者的变量提升一致吗?此时你的答案是什么?
接下来让我们来探讨这两个问题,如有错误敬请指正。
1. let存在提升
对于let
是否存在提升这个问题,让我们先来看以下这段代码:
a = "global"; (function() { console.log(a); // undefined, 而不是打印出global var a; }()); { console.log(a); // Uncaught ReferenceError: Cannot access 'a' before initialization let a = 1; }
对于在函数作用域下打印出undefined
,我们应该不奇怪。但引起我注意的是在块作用域下,抛出引用错误的原因是在初始化之前找不到a
。那有没有可能a
在创建过程被提升?而在我发现ES文档中存在[var/let hoisting]
,这让我有理由猜测let
存在提升,只是由于暂时性死区的原因,我们不能在let a
之前使用 a
。
为了证明我的猜想,我想先从let
声明的创建、初始化和赋值过程入手。
{ let a = 0; a = 1; }
上述的代码块中发生的过程如下:
- 找到所有用
let
声明的变量,在环境创建变量; - 执行代码;
- 执行
a=0
,将a
初始化为1; - 执行
a=1
,对a
进行赋值。
由该过程可知,如果我们在创建完变量后和初始化之前执行log()
方法,控制台将会报错:
let a = 'global' { console.log(a) // Uncaught ReferenceError: Cannot access 'a' before initialization let a = 1 }
由此一来我们就可以知道了let
在创建的过程被提升,而在初始化过程没有被提升。
2. var/function的变量提升
接下来我们来看看function/var
的创建、初始化和赋值过程,由此看看能否探究出它们的差别。
2.1 var的变量提升
function foo() { console.log(a); // undefined var a = 0; var b = 1; } foo();
当我们执行foo()
时,发生以下过程(较为省略):
- 为
foo
创建环境; - 找到
foo
中所有被var
声明的变量,在这个环境中创建变量; - 将变量初始化为 undefined;
- 执行代码;
- 将
a
赋值为0,b
赋值为1。
由此我们可以知道var
声明在代码执行前创建变量并初始化,所以当我们在var a = 0
之前执行log(a)
方法会得到 undefined 的结果。
2.2 function的变量提升
foo('btqf'); function foo(name) { console.log("my name is" + name) // my name is btqf }
当我们执行foo
函数时,发生以下过程:
- 找到所有
function
声明的变量,在环境中创建变量; - 将这些变量初始化并赋值;
- 执行代码。
由此可见,function
声明在代码执行前就创建、初始化并赋值。
3. 总结
let
的「创建」过程被提升了,但是初始化没有提升。var
的「创建」和「初始化」都被提升了。function
的「创建」「初始化」和「赋值」都被提升了。- 函数和变量相比,会被优先提升,即函数会被提升到更靠前的位置。
值得一提的是const
与let
基本类似,唯一的区别在于const
只有创建和初始化,没有赋值过程。
到此这篇关于深入了解JavaScript中let/var/function的变量提升的文章就介绍到这了,更多相关let/var/function变量提升内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!