let、var、const声明的区别


前言

看了方应杭老师的一篇解释let的文章,对JavaScript中的声明有了深刻的理解,这里也就有了总结一下JavaScript中各种声明之间区别的这篇文章。

JavaScript中变量声明机制

首先,我对JavaScript中所有声明都存在提升这个观点是认同的!

平时大家所讲的变量的声明,在JavaScript中一般是存在创建create初始化initialize赋值assign三个过程的,其中函数声明也是一样有这三个过程的。在这三个过程中:

创建:即在变量所在作用于头部抛出变量,仅仅是抛出,是不能被使用的;
初始化:在变量初始化之前变量是不能被使用的,初始化只有一次,初始化之后变量可以使用;
赋值:即覆盖初始化的值

在let、var、const(包括函数声明)的声明过程中,他们的创建create初始化initialize赋值assign是有区别的。

let

let是ECMAScript2015(ES6)中新增的变量声明方式,let语句可以声明一个块级作用域的变量。

在同一个函数或同一个作用域中用let重复定义一个变量将引起 TypeError

if (true) {
  let foo;
  let foo; // TypeError thrown.
}

在let语句中,创建create初始化initialize赋值assign的过程如下:

if (true) {
  let foo
  console.log(foo) //undefined
  foo = 'str'
  console.log(foo)  //"str"
}

通过上面代码可以看出let语句是如下过程的:

第一步:在块级作用域中,找到let语句并声明提升,创建foo变量,但是在初始化之前使用是会报错的(如下面代码);
第二步:执行let foo,let语句使得foo变量被初始化,初始化的过程是可选的,可以let foo初始化foo为undefined,也可以let foo = 123初始化foo为123.初始化之后变量可以使用;
第三步:执行foo = 'str',foo变量可以被赋值语句覆盖

if (true) {
  console.log(foo) //Uncaught ReferenceError: foo is not defined
  let foo;
}

所以说,let声明中在初始化之前是存在“暂时性死区”的。

还有值得注意的是,初始化只能一次,如果变量初始化失败,则会存在一个该变量既不能赋值又不能使用的BUG,如下图:

因为let foo = foo导致初始化失败,所以导致了foo所在作用域都是foo变量只创建而未被初始化,所以foo所在作用域都会是foo变量的“暂时性死区”

var

var声明是函数作用域。
众所周知,var声明是有变量提升的,有了上文的let声明的理解,也就对var理解起来更加轻松了。

(function() {
  console.log(f) //undefined
  var f = 'str' //
  console.log(f) //"str"
}())

var声明的过程:

第一步:在函数作用域中,找到var语句,f变量得到声明提升到作用域顶部,创建f变量并初始化为undefined,在赋值之前f的值就是undefined;
第二步:执行f = 'str',f变量被赋值为'str'

所以,在执行var f = 'str' 之前,打印的f的值为undefined

const

const声明创建了一个常量
const和let比较像,也是块级作用域,区别就是,const在定义的时候必须初始化,而且不能被赋值

如上图,const在定义时必须初始化,否则会报错Uncaught SyntaxError: Missing initializer in const declaration;const是常量,声明之后不能再次赋值,否则会报错Uncaught TypeError: Assignment to constant variable

函数声明

函数声明在JavaScript存在变量提升,这也被众多开发者做开发所常用。

fn()
function fn(){
  console.log(this)
}

函数声明的过程:

第一步:在作用域中,找到function语句,将fn函数声明提升到作用域顶部,创建fn函数,初始化并赋值为function fn(){console.log(this)}
第二步:执行fn()

即函数声明是在找到function语句后,作用域顶部创建、初始化和赋值一步到位的

总结

MDN关于let讲解中,说let没有声明,也许是考虑到更容易被开发者接受和理解吧,但是我认为JavaScript中所有声明都存在提升是正确的。

最后用一个表格总结一下let、var、const声明的区别吧

--- let var const
变量or常量 变量 变量 常量
作用域 块级作用域 函数作用域 块级作用域
创建 作用域顶部创建 作用域顶部创建 作用域顶部创建
初始化 let语句 作用域顶部 const语句
赋值 可以赋值 可以赋值 报错
重复声明 报错 可以重复声明 报错
暂时性死区 没有

本文首发在个人博客yoowin.me,欢迎访问。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM