JavaScript 深入学习——变量

ECMAScript 变量是松散类型的,意思是变量可以用于保存任何类型的数据。每个变量只不过是一个用于保存任意值的命名占位符

变量声明

var

  • var 声明语句声明一个变量,并可选地将其初始化为一个值。
  • 变量声明无论发生在何处,都在执行任何代码之前进行处理(即变量提升)。
  • var声明的变量的作用域是它当前的执行上下文(全局作用域函数作用域
  • 声明非声明的变量存在以下3点差异:
    1. 声明变量的作用域限制在其声明位置的上下文中,而非声明变量总是全局的。
    2. 声明变量在任何代码执行前创建,而非声明变量只有在执行赋值操作的时候才会被创建(非声明变量在未赋值前调用,将会抛出错误)。
    3. 声明变量是它所在上下文环境的不可配置属性,非声明变量是可配置的(如非声明变量可以被删除)。

let

  • let 语句声明一个块级作用域的本地变量,并且可选的将其初始化为一个值。与var关键字不同的是,var声明的变量只能是全局或者整个函数块的。
  • let不会在全局声明时(在最顶部的范围)创建window对象的属性。
  • 在同一个函数或块作用域中重复声明同一个变量会引起SyntaxError
  • 通过 let声明的变量直到它们的定义被执行时才初始化。在变量初始化前访问该变量会导致ReferenceError。该变量处在一个自块顶部到初始化处理的**“暂存死区”**中。

const

  • const 语句声明一个块级作用域的本地常量,并且必须将其初始化为一个值。但常量的值是无法(通过重新赋值)改变的,也不能被重新声明。
  • const 特性除不能被重新被赋值外,其他特性基本与let 相似。
  • const 的值是一个引用时,只要不修改其引用,可以对引用值内容进行操作。

变量提升(Hoisting

变量提升(Hoisting)被认为是, Javascript中执行上下文 (特别是创建和执行阶段)工作方式的一种认识。在 ECMAScript® 2015 Language Specification 之前的JavaScript文档中找不到变量提升(Hoisting)这个词。

变量提升是指将变量和函数的声明提升到作用域顶部。注意提升的只是声明,定义并没有被提升。如语句var a = 2 会被拆分为var aa = 2 ,变量声明var a会被提升到作用域顶部,而定义a = 2 位置不变。

变量提升的本质其实是js引擎在编译的时候,就将所有的变量声明了,因此在执行的时候,所有的变量都已经完成声明。

将变量、函数的整个产生的过程分为【创建、初始化和赋值】


对于var变量,其过程如下:
1.进入一个作用域(全局作用域或函数作用域);
2.找到当前作用域中所有用 var 声明的变量,在这个环境中「创建」这些变量;
3.将这些变量「初始化」为 undefined
4.开始执行代码
5.当执行到变量赋值语句时,开始赋值
也就是说 var 声明会在代码执行之前就将「创建变量,并将其初始化为 undefined」。


对于function函数,其过程如下:
1.找到所有用 function 声明的变量,在环境中「创建」这些变量。
2.将这些变量「初始化」并「赋值」为 function(){ // ... }
3.开始执行代码
也就是说 function 声明会在代码执行之前就「创建、初始化并赋值」。

对于let变量,其过程如下:
1.找到所有用 let 声明的变量,在环境(块作用域)中「创建」这些变量
2.开始执行代码(注意现在还没有初始化)
3.代码运行到声明处,如let x = 1 ,此时将x「初始化」为1 ,如果没有初始值,则初始化为undefined
4.如果再执行到如x = 2 的语句时,才是对x进行「赋值」


对于const常量,它与let的区别是没有「赋值」的过程。


总结:
1.var的「创建」和「初始化」都被提升了。
2.function 的「创建」「初始化」和「赋值」都被提升了。
3.let / const 的「创建」过程被提升了,但是初始化没有提升。

所以let和const声明的变量也是有变量提升的

暂时死区TDZ(Temporal Dead Zone)

暂时死区,在网上也有很多叫暂存(性)死区。

let/const声明的变量,当它们包含的词法环境(Lexical Environment)被实例化时会被「创建」,但只有在变量的词法绑定(LexicalBinding)已经被求值运算【初始化】后,才能够被访问。也就是说,在程序中,变量「创建」之后「初始化」之前的这部分区域,该变量是不能被访问的,对这个变量而言,这是它的暂时死区TDZ

let/const声明的变量或常量,必需是经过对声明的赋值语句的求值后,才算初始化完成,创建时并不算初始化。如果以let声明的变量没有赋给初始值,那么就赋值给它undefined值。也就是经过初始化的完成,才代表着TDZ期间的真正结束,这些在作用域中的被声明的变量才能够正常地被访问。

块作用域

被大括号(“{}”)包裹起来的指令集合(代码块)形成一个块作用域。对于function语句和for语句,括号内声明的变量的作用域在紧跟其后的块作用域中。

function fn(a, b) {
	// a 和 b 的作用域在这个块作用域中
}

for(let x = 0; x < 10; x++) {
	// x 的作用域在这个块作用域中
}

参考

let深入理解—let存在变量提升吗?

理解es6中的暂时性死区

MDN——let

MDN——var

MDN——const

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值