ES6学习笔记:let var const 的区别

566 阅读4分钟

一、 变量提升

在当前执行上下文中,代码执行之前,浏览器首先会把所有带var或者function的关键字进行提前声明或定义。

老版本浏览器:带 var 的只是提前声明,带 function 会提前声明 + 定义(赋值)

新版本浏览器(兼容ES5 & ES6):存在块级上下文,function:大括号中的函数(非函数和对象),在变量提升阶段,只声明不赋值。

  • 条件判断:在当前上下文中,变量提升阶段,不论条件是否成立,都要进行变量提升。
    • var:还是只声明
    • function:判断体中的函数,在变量提升阶段,只声明不赋值。
    console.log(a)
    if(!('a' in window)){
     var a = 13
    }
    console.log(a)
    // undefined undefined
    

let,const就不会引起变量提升,因此在写函数时,最好使用函数表达式的方式创建函数,如:

let fn = function(){}
fn()

举个栗子:

fn()
function fn(){console.log(1)} //(1)
fn()
function fn(){console.log(2)}  //(2)
fn()
var fn = function (){console.log(3)}  //(3)
fn()
function fn(){console.log(4)}  //(4)
fn()
function fn(){console.log(5)}  //(5)
fn()

分析: 根据上述知识点可知道,代码执行前遇见function就会提前声明并定义(就是把function指向的堆内存地址赋值给fn),遇见var提前声明,因此:

//变量提升:

(1) => fn = aaafff111 (function的堆内存地址,自定义的)
(2) =>      aaafff222
(3) =>      
(4) =>      aaafff444
(5) =>      aaafff555   

//代码执行:按照顺序执行fn(),依次打印 5 5 5
//运行到第六行时,因为之前只是声明,所以现在开始执行赋值操作,此时fn 指向 aaafff333 地址
//继续执行,依次打印 3 3 3

结果:

 5 5 5 3 3 3

二、 总结

1. 变量提升

  • 使用 var 声明变量 会引起变量提升
  • letconst不会。let,const未声明就使用会报错

2. 给全局添加属性

全局上下文中,

  • 基于var声明的变量不是存放在VO(G)中,而是直接存放在GO(window)中;「新浏览器」
  • 基于let/const声明的变量存放在VO(G)中,不存放在GO中
var x = 1;
console.log(window.x) //1
let y = 1
console.log(y) // 1
console.log(window.y) //undefined

3. 重复声明

  • var的是可以重复声明的(词法解析可以审核通过),执行阶段遇到已经声明过的不会再重新声明;
  • let/const不可以,词法解析阶段发现在相同上下文中,基于let重复声明变量的操作,则直接报错,所有代码都不会执行。

    在当前上下文中不论基于什么方式声明了这个变量,再次基于let/const声明都会报重复声明错误

    var a = 1

    let a = 1

4. 块级作用域

没有ES6之前,作用域只有2种:全局作用域,函数作用域。有了let后,产生了块级作用域,如果在{}中出现let/const/function,则当前{}会成为一个块级私有上下文。「{}排除函数和对象的{}」

let存在块级作用域,var没有。 对于循环来说,let会形成父块作用域。每一轮循环形成子块作用域,创建一个私有变量,值由父块作用域传进来,每执行完一轮循环,循环累计数i加1。

ES6中常写循环的方式:

let arr=[10,20,30]
for(let i = 0;i<arr.length;i++){}

以上会创建出4个块级作用域,每轮循环都会再对arr的length做计算,虽然最终都会被释放掉,但可以有更优写法

// ES6中正常循环,使性能更优的写法
let arr=[10,20,30]
let i = 0,
    len = arr.length
for(;i<len;i++){} 

5. 暂时性死区

在代码块内,使用let。const命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”

a为未定义变量,直接使用不报错

console.log(typeof a) //undefined

在代码块里,用let或const声明了变量再之前使用就会报错

console.log(typeof a) //报错
let a

6. let与const

let和const都是ES6新增的用于创建变量的语法。

let创建的变量是可以更改指针指向(可以重新赋值)。

但const声明的变量是不允许改变指针的指向,不能重新赋值。不代表值不能变

const a = {
 name:'hello'
}
a.name = 'world'
console.log(a) // {name:'world'}

补充1:Js代码执行

  • 词法解析(AST):我们基于HTTP服务从服务器端拉回来的js代码都是字符串,浏览器首先按照ECMAScript规则,把字符串转换成C++可识别和解析的树结构对象
  • 全局上下文
    • 变量提升
    • 代码执行
    • ...