欢迎光临
我们一直在努力

JavaScript | 变量提升与暂时性死区

var let 及 const 区别

先来了解提升(hoisting)这个概念。

console.log(a) // undefined
var a = 1

从上述代码中我们可以发现,虽然变量还没有被声明,但是我们却可以使用这个未被声明的变量,这种情况就叫做提升,并且提升的是声明。

var a
console.log(a) // undefined
a = 1

接下来我们再来看一个例子

var a = 10
var a
console.log(a)

对于这个例子,如果你认为打印的值为 undefined 那么就错了,答案应该是 10,对于这种情况,我们这样来看代码

var a
var a
a = 10
console.log(a)

到这里为止,我们已经了解了 var 声明的变量会发生提升的情况,其实不仅变量会提升函数也会被提升。

console.log(a) // ƒ a() {}
function a() {}
var a = 1

对于上述代码,打印结果会是 ƒ a() {},即使变量声明在函数之后,这也说明了函数会被提升,并且优先于变量提升。

说完了这些,想必大家也知道 var 存在的问题了,使用 var 声明的变量会被提升到作用域的顶部,接下来我们再来看 let 和 const 。

我们先来看一个例子:

var a = 1
let b = 1
const c = 1
console.log(window.b) // undefined
console.log(window. c) // undefined

function test(){
  console.log(a)
  let a
}
test()

首先在全局作用域下使用 let 和 const 声明变量,变量并不会被挂载到 window 上,这一点就和 var 声明有了区别。

再者当我们在声明 a 之前如果使用了 a,就会出现报错的情况

报错的原因是因为存在暂时性死区,我们不能在声明前就使用变量,这也是 let 和 const 优于 var 的一点。

ES6 明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。 总之,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。

那么到这里,想必大家也都明白 varlet 及 const 区别了,不知道你是否会有这么一个疑问,为什么要存在提升这个事情呢,其实提升存在的根本原因就是为了解决函数间互相调用的情况

function test1() {
    test2()
}
function test2() {
    test1()
}
test1()

假如不存在提升这个情况,那么就实现不了上述的代码,因为不可能存在 test1 在 test2 前面然后 test2 又在 test1 前面。

另外,指的一提的的是ES6中的箭头函数不会进行变量提升,实际上箭头函数属于字面量函数,只有当执行到当前行时,函数才会完成创建。

最后总结一下:

  • 函数提升优先于变量提升,函数提升会把整个函数挪到作用域顶部,变量提升只会把声明挪到作用域顶部
  • var 存在提升,我们能在声明之前使用。letconst 因为暂时性死区的原因,不能在声明前使用
  • var 在全局作用域下声明变量会导致变量挂载在 window 上,其他两者不会
  • let 和 const 作用基本一致,但是后者声明的变量不能再次赋值

最后附上JS解析器工作原理:

JS解析器浏览器中有一套专门解析JS代码的程序,这个程序称为js的解析器。浏览器运行整个页面文档时,遇到<script>标签时JS解析器开始解析JS代码。

JS解析器的工作步骤:

1、预解析代码 

主要找一些关键字如var、function、参数等,并存储进仓库里面(内存); 

变量的初始值为 undefined;  

函数的初始值就是该函数的代码块;  

当变量和函数重名时:不管顺序谁前谁后,只留下函数的值; 

当函数和函数重名时:会留下后面那个函数。

2、逐行执行代码  

当预解析完成之后,就开始逐行执行代码,仓库中变量的值随时都可能会发生变化

赞(0) 打赏
未经允许不得转载:散人研 » JavaScript | 变量提升与暂时性死区
分享到: 更多 (0)

评论 抢沙发

8 + 4 =
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏