var&let&const的区别

吐槽君 分类:javascript

变量提升


var声明的变量会发生“变量提升”,即在变量没有声明之前就调用该变量

console.log(aimer) // undefined
var aimer = "march of time"
 

之所以会造成变量提升是因为在执行JS代码之前浏览器会对JS代码进行预解析,将var声明的变量 以及function函数提升到顶部,上面代码经过预解析之后是这样

var aimer 
console.log(aimer)
aimer = "march of time"
 

let const则不会发生"变量提升"

console.log(aimer) //  Cannot access 'aimer' before initialization
let aimer ="march of time"
 
console.log(aimer) //  Cannot access 'aimer' before initialization
const  aimer ="march of time"
 

块级作用域


var声明的变量只有函数作用域和全局作用域 不具备块级作用域,例如喜闻乐见的面试题,点击当前的li拿到当前的索引!

 <ul>
      <li>0</li> //5
      <li>1</li> //5
      <li>2</li> //5
      <li>3</li> //5
      <li>4</li> //5
    </ul>
 let lis = document.querySelectorAll('li')
      for (var i = 0; i < lis.length; i++) {
        lis[i].onclick = function () {
          console.log(i)
        }
      }
 

上面代码无论点击哪一个打印的都会是5,因为for循环是同步而点击事件是异步,在点击之前循环已经结束.尽管每一次循环声明的变量值都自增1,但因为没有块级作用域(for循环用var声明的变量会泄漏为全局变量)并没有有效的保存那些变量值,导致点击任何一个li得到的都是lis的最大长度。

<ul>
      <li>0</li> //0
      <li>1</li> //1
      <li>2</li> //2
      <li>3</li> //3
      <li>4</li> //4
    </ul>
 let lis = document.querySelectorAll('li')
      for (let i = 0; i < lis.length; i++) {
        lis[i].onclick = function () {
          console.log(i)
        }
      }
 

而使用let来声明则可以避免这种奇怪的现象,let声明的变量具有块级作用域,每次循环都创建了一个块级作用域来保存当前的变量.确保每次拿到的变量和之前的值不一样!

不允许重复声明


在同一个作用域下用let重复声明变量会报错,var重复声明不会报错

     // 报错
      function aimer() {
        let aimer = 30
        var aimer = 20
      }
      // 不报错
       function aimer() {
        var aimer = 30
        var aimer = 20
      }
 

暂时性死区(TDZ)


ES6 明确规定,如果区块中存在letconst命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。

     if (true) {
        aimer = 're:pary'  //报错 
        console.log(aimer) // 报错
        let aimer
      }
 

const指令


constlet有许多共同之处(块级作用域 暂时性死区 不可重复声明 不具备变量提升 ),但也有些细微的不同.

  • const定义的常量必须马上赋值否则会报错 let不会
  const aimer // 报错
  let aimer // 不报错
 
  • const声明的是只读的常量 不可更改

尽管const声明的常量不可更改,但实际上保证的常量的内存地址不能更改,如果const声明的是数组或者对象,在不修改内存地址的前提下依然可以修改里面的属性

     const aimer = { sing: 'march of time' }
     aimer.age = 29
     console.log(aimer) // sing:'march of time' age:29
     
     const aimer = ['Tone']
     aimer.push('Lris')
     console.log(aimer) // [Tone Lris]
 

如果要让const定义的常量完全不能更改也可以通过Object.freeze来冻结那些属性或者利用Object.defineProperty里面的writable属性来控制是否可以修改

   const aimer = { sing: 'Tone' }
     Object.freeze(aimer)
     aimer.sing = 'Save'
     console.log(aimer) // {sing:'Tone'}
     
     const aimer = { sing: 'Tone' }
     Object.defineProperty(aimer, 'sing', {
       writable: false
     })
     aimer.sing = 'Save'
     console.log(aimer) // {sing:'Tone'}
 

总结

  • var 具有变量提升 let const没有
  • var 没有块级作用域 let const有
  • var 在同一个作用域下可以反复声明 let const不行
  • let const 有暂时性死区 var没有
  • let const 必须先定义在使用否则报错 var不会

以上是个人对var let const的理解如有错误欢迎指正

回复

我来回复
  • 暂无回复内容