11、 let和var的区别

157 阅读4分钟

一、声明变量的五种方式

  1. 传统方式:var、function
  2. ES6: let、const、import

二、let VS const

  1. let和const声明的都是变量,const声明的变量是不允许指针重新指向的(但是存储的值是可以改变的,例如:存储的值是引用数据类型,可以基于地址改变堆内存中的信息)
    赋值本身就是指针关联或者指针指向的过程

    // let声明的变量可以修改
    let n = 12
    n = 13
    console.log(n) // 13
    
    // const声明的不可以直接修改
    const m = 12
    m = 13
    console.log(m) // Uncaught TypeError: Assignment to constant variable.  
    
    // const声明的变量基于地址改变堆内存中的信息
    const obj = {
    	name: 'zs'
    }
    obj.name = 'ls'
    console.log(obj) // {name:'ls'}
    
    

三、let VS var

  1. 带var/function的存在变量提升,而let/const不村子啊变量提升机制
    在全局代码执行之前,首先会变量提升:把当前上下文中所有带var/function关键字的提前声明(带var的只声明不定义,带function的会提前声明+定义)
// 带var的会变量提升
console.log(n) // undefined
var n = 12 

相当于

var n
console.log(n)
n = 12
console.log(n) // VM226:1 Uncaught ReferenceError: Cannot access 'n' before initialization   不允许再声明之前使用它
let n = 12

之前创建函数都是 function fn() {} 但是现在不建议这么写,举例

// 变量提升: fn = 0x0000(堆内存)
fn() // ok
function fn() {
	console.log('ok')
}

在函数创建之前可以正常使用,正常情况下应该是创建完后才能使用,所以这么写不严谨

现在建议用函数表达式创建函数

fn() // Uncaught ReferenceError: Cannot access 'fn' before initialization
const fn = function() {
	console.log('ok')
}

这么写保证了严谨性

函数的变量提升在“新版本浏览器”中得坑爹机制

变量提升阶段:<br>
1. 没有出现在大括号当中,在新老版本中是一样的,都是声明加定义
2. 出现在大括号当中:<br>
<span style="color:red">[老版本浏览器]:</span>不论条件是否成立,都要把fn声明+定义,而且fn
只是全局上下文中得变量<br>
<span style="color:red">[新版本浏览器]:</span>为了兼容ES3/ES6,规则处理的非常复杂

 2.1. 全局变量提升:如果创建函数的代码出现在"非函数或者对象得大括号中(例如:判断题,循环体,代码块...)",只会进行声明,不进行赋值了 =》 function fn;

    console.log(fn) // 老版本浏览器中输出函数本身。 新版本浏览器中 输出undefined
    if(1==1){
    	function fn() {
        	console.log('ok')
        }
    }
   
   2.2. 代码执行进入到大括号当中:如果大括号中有function此时function xxx(){},此时当前大括号会形成一个私有的上下文,私有上下文中的第一件事情也是变量提升,它会把函数进行声明+定义(私有变量)
   
   
    console.log(fn) // 老版本浏览器中输出函数本身。 新版本浏览器中 输出undefined
    if(1==1){
    	// 私有上下文变狼提升:fn = 0x000000
    	console.log(fn) // 函数
    	function fn() { // 代码执行大这的时候,会把私有赏析文中,之前对fn的操作,映射给全局一份
        	console.log('ok')
        }
        fn = 12
        console.log(fn) // 12
    }
    console.log(fn) // 函数

所以,真实项目中尽量不要把函数写在非函数/对象的大括号中。并且创建函数的时候尽可能用函数表达式

  1. 第二个区别。相同的上下文中,let不允许重复声明(而且检测是否重复声明发生在“词法解析阶段” 词法解析->变量提升->代码执行,也就是词法解析阶段检测到重复声明,则直接报错,代码一行都不会执行。);且不论基于什么方式声明的变量,只要在当前上下文中有了,则不允许再基于let/const声明。

词法解析阶段检测到重复声明,则直接报错,代码一行都不会执行

3. 暂时性死区(浏览器遗留BUG):基于typeof 检测一个未被声明的变量,不会报错,结果是undefined

但是如果在let声明之前用就会报错,所以可以理解为使用let 能解决浏览器暂时性死区问题 4. 块级私有上下文(作用域):
1.除函数或者对象的大括号之外,如果括号中出现 let/const 则会产生块级私有上下文
2.当前块级上下文也只是对let/const/function他们声明的变量有作用。 可以这么理解:
不会形成块级私有上下文

会形成块级私有上下文