var let和const的区别(全面剖析)

84 阅读6分钟

须知:

1.什么是变量提升?

Java****Script 中,函数及变量的声明都将被提升到函数的最顶部。

JavaScript 中,变量可以在使用后声明,也就是变量可以先使用再声明

2**.全局作用域 :变量在函数外定义,即为****全局变量**。全局变量有 全局作用域: 网页中所有脚本和函数均可使用。

局部作用域:变量在函数内声明,变量为****局部作用域局部变量只能在函数内部访问(在{}内有效,{}外是无效的)。

面向对象原则:高内聚、低耦合。多聚合、少继承

暂时性死区:只要一进入当前作用域,所要使用的变量就已经存在,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。

var命令

1.声明一个函数作用域或全局作用域变量,可以选择将其初始化为一个值。

2.它可以是嵌套的函数,或者对于声明在任何函数外的变量来说是全局。如果你重新声明一个 JavaScript 变量,它将不会丢失其值。var定义的变量会预解析,简单的说就是如果变量没有定义就直接使用

3.只声明,不赋值,结果undefined

var age;console.log(age);//undefined

4.不声明不赋值,直接使用,报错

console.log(age);//报错

5.不声明,只赋值,返回结果

var age=10;console.log(age);//10

let命令

  1. 循环体的let变量只对花括号作用域可见,花括号外不可见
  2. 循环体的语句部分是一个父作用域,而循环体内部是一个单独的子作用域
  3. let声明的变量不存在变量提升,未声明的使用会报错,暂时性死区
  4. 只要块级作用域内存在let声明,它所声明的变量就绑定了这个区域,不再受外部的影响
  5. let不允许在相同的作用域重复声明同一个变量,子父级作用域可以同名变量声明

const命令

  1. const常量的值一旦声明就不得改变
  2. const一旦声明变量,就必须立即初始化,不能留到以后赋值
  3. const的作用域与let命令相同,只在声明所在的块级作用域内有效
  4. const命令同样存在暂时性死区,只能在声明的位置后面使用
  5. const声明的常量,也与let一样不可重复声明
  6. 对于复合类型的变量,变量名不指向数据,而是指向数据所在的地址,所以const命令只是保证变量名指向的地址不变,并不保证该地址的数据不变

let和const命令的声明不再自动纳入global对象(window)

块级作用域与函数声明

  1. ES6的浏览器下,块级作用域内声明的函数会被提升至全局作用域或函数作用域顶部,作为var fn = undefined
  2. 其他的游览器下,还是将块级作用域的函数声明当作let处理
  3. 应该避免在块级作用域内声明函数,如果确实需要也应该使用函数表达式而不是函数声明
  4. ES6的块级作用域允许声明函数,但只在使用大括号的情况下成立,如果没有使用大括号就会报错

区别:

1.var声明变量存在变量提升,let和const不存在变量提升

console.log(a); // undefined  ===>  a已声明还没赋值,默认得到undefined值
var a = 1;
console.log(b); // 报错:b is not defined  ===> 找不到b这个变量
let b = 2;
console.log(c); // 报错:c is not defined  ===> 找不到c这个变量
const c = 3;

变量提升,不执行的代码也影响执行的代码

function fn() {
   //var a
    if (true) {
        console.log(a+'b')
    }
    else {
        var a = 1
        console.log(2)
    }
}

fn() // a -> undefined

2.全局变量var,块级局部变量let和const

var定义的变量在全局作用域上,全局共享,在方法中用定义的var只有该方法内生效。

块级局部变量,就是在当前代码块内有效。

{
  let a=10;
}
console.log(a)//undefined

const声明时必须赋值

const a//报错

const只能赋值一次,声明后不能修改,常用来定义常量

**优先级var<let<const,**但是实际中最常用的是let

var定义变量容易造成全局污染,一旦被修改全局都要修改,造成低内聚,高耦合

  首先const声明常量的好处,一是阅读代码的人立刻会意识到不应该修改这个值,二是防止了无意间修改变量值所导致的错误,另外其实js编译器也对const进行了优化,可以提高代码的执行效率;

   另外let声明的变量没有预编译和变量升级的问题,先声明再使用其实更为规范,而let本身是一个块级作用域,很多时候我们在写代码的时候都希望变量在某个代码块内生效,也更为方便。

  最后说一点就是使用的场景说明:let一般应用于基本数据类型;const 一般应用于引用数据类型,也就是函数对象等。

const a=10;
a=20;//报错(控制台,编译器)

3.同一个作用域下,let 可以更新,但不能重新声明,var 变量可以重新声明和更新(覆盖栈中的值),const 无法更新或重新声明

let a=1;
let a=3;
//报错(控制台,编译器)

面试题

for(let i=0;i<3;i++){
  console.log(i)
}
//打印:0,1,2
//我再来问大家,此时i等于几?题解最后看答案

//回归正题
//正常理解是i在()作用域内,打印不出来,但是实现机制导致let的作用域不是我们理解的那样
//可以这样理解
for (let _i = 0; i < 5; i++) {
 // 每次循环创建一个i
    let i = _i
    console.log(i)
    //最后i++后再将变量i的值赋值回_i上, i++ 先做
    _i = i
}
//答案i=3,因为i=3到这里就不执行了

隐秘死区
function fn (x = y , y = 2) {
        return [x,y]
    }
    fn() // Error:Cannot access 'y' before initialization
    //y没有被定义却被x使用了

    var a = a;
    let b = b;


  作用域问题
if(true) {
        // 暂时性死区开始
        name = "cht" ;// Error
        console.log(name); //Error

        let name; // TDZ结束
        console.log(name); // undefined

        name = "hw";
        console.log(name); // hw
    }
----------------------------------------------------------------------------------------
 !function fn() {
     var a = 5;
  }()
  console.log(a); // Error:a is not defined  外部访问不到
// 等同于 

{
    var a = 5
}

注意:

  • 块级作用域允许相互嵌套
  • 外层作用域不能访问内层变量
  • 不同层级作用域可以定义同名变量
  • es6允许在块级作用域下声明函数,在块级作用域外面不可引用
  • 凡是有{}者都有块级作用域
  • ES6的块级作用域必须有大括号 {} 如果没有{} js引擎认为不存在块级作用域