4

var、let和const之间的区别

 2 years ago
source link: https://www.clzczh.top/2022/04/13/js-let-var-const/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

var、let和const之间的区别

作用域不同

var是函数作用域, letconst是块级作用域

  • 函数作用域就是在函数中声明了 var变量,那么这个变量在整个函数里都是有效的。

  • 块级作用域则是在块里是有效的。块级作用域就是用{}包住的区域,常用的有forwhileif等,只是有 {}包住也是块级作用域

{
  var a = 111
  let b = 222
  const c = 333

  console.log(a)  // 111
  console.log(b)// 222
  console.log(c)// 333
}

console.log(a)  // 111
// console.log(b) // b is not defined
console.log(c)  // c is not defined

有无变量提升

var有变量提升, let const没有变量提升

let const不需要先声明,再使用,否则会报错,而 var不需要先声明再使用,可以先使用后声明,不会报错,不过赋值的时候,值一直是 undefined

console.log(a)    // undefined
console.log(b)    // Cannot access 'b' before initialization
// console.log(c)  // Cannot access 'c' before initialization

var a = 111
let b = 222
// const c = 333

**注意,这里报的错不是 b is not defined而是 Cannot access 'b' before initialization**。也就是说:

  • 从广义上来说, let const没有变量提升,因为在声明前使用会报错
  • 从狭义上来说, let const是有变量提升的,因为实际上用它们定义的变量已经被执行上下文记住了,否则应该会报错 is not defined才对。

let const究竟有没有变量提升取决于怎么定义变量提升

  • 如果变量提升指的是变量可以在声明前使用,则没有变量提升
  • 如果变量提升指的是变量在声明前有没有被执行上下文记住的话,则是有变量提升的。

能否被重新定义

let const不能被重新声明,但是var可以被重新声明

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

// let b = 1
// let b = 2    // Identifier 'b' has already been declared

// const c = 1
// const c = 2     // Identifier 'b' has already been declared

在这个例子中,把下面的注释去掉后,就能够再次证明上面说的 letconst有没有变量提升是取决于怎么定义的。

image-20220411210448047
image-20220411210448047

因为JavaScript是单线程的,如果预编译执行上下文没有记住用 let const定义的变量的话,按理来说会先输出a,才报错,但是不是,也就是说,实际上执行上下文在预编译的时候,也已经记住用 let const声明的变量了。

不能在函数内部重新声明参数

function mytest(args) {
    let args	// 报错
}

但是,如果是在函数里的另一个块级作用域里则可以重新声明参数

function mytest(args) {
  {
    let args = 111;
    console.log(args)	// 111

    {
      let args = 222;
      console.log(args)	// 222
    }

  }
}

mytest(123)

暂时性死区

块中用 let const声明的变量,在使用 let const声明变量之前,该变量都是不可用的。这在语法上称为暂时性死区(temporal dead zone)

var a = 111

{
  console.log(a)    // Cannot access 'a' before initialization
  let a = 222
}

上面的例子,就是典型的暂时性死区的例子。在上面有全局变量,在下面有块级变量,但是在中间则是谁都没法访问到。

全局作用域下是否会挂载到window对象

全局作用域下,使用 var声明的变量会被挂载到 window对象上,而使用 let const 则不会

var a = 111
console.log(window.a)   // 111

let b = 222
console.log(window.b)   // undefined

const c = 333
console.log(window.c)   // undefined

constlet的区别

const var的区别如上。 const let的区别就是const声明的是常量,声明后不能够修改

常见面试题

for (var i = 0; i < 5; i++) {
  setTimeout(function () {
    console.log(i)    // 输出5,5次
  }, 0)
}

因为setTimeout是宏任务(JS执行机制可参考之前的文章),所以执行输出语句时,for循环已经执行完成了,然后用 var声明的变量是函数作用域,所以会打印出5个5。可以尝试在for循环外打印i,能得到 5的结果

把上面的 var换成 let后,会依次输出0、1、2、3、4

for (var i = 0; i < 5; i++) {
  setTimeout(function () {
    console.log(i)    // 输出0、1、2、3、4
  }, 0)
}

因为 let是块级作用域,用 let声明的变量会被绑定到 setTimeout上,所以并不会受到外界的影响,输出的结果就会是正常的0、1、2、3、4。

另外,for循环还有一个特别的地方:设置循环变量的部分是一个父作用域,而循环体内是一个单独的子作用域

for (let i = 0; i < 1; i++) {
  let i = 222       // 这里不会报错,因为这里实际上是另一个子作用域
  console.log(i)    // 222
}

这里顺便再来回顾一下,暂时性死区。

for (let i = 0; i < 1; i++) {
  console.log(i)		// Cannot access 'i' before initialization
    
  let i = 222      
  console.log(i)   
}

参考链接:


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK