文章目录
- 前言
- var
- 变量提升
- let
- 暂时性死区
- 具体的区别
- 声明后未赋值,表现相同
- 使用未声明的变量,表现不同
- 重复声明同一个变量时,表现不同
- 变量作用范围,表现不同
在JavaScript中我们每时每刻都在声明变量、使用变量,在之前我只知道var,后面我发现同事们都在写let,我在半知半解的情况下同时使用了这两种声明方式,结果就报错了。所以在这里写一篇文档来详细说明两种声明方式的区别。
前言
在ES6中JS引入了let,在ES5之前都是使用var进行变量声明。let主要用于声明局部变量。它的用法类似于var,但是ES6也引入了块级作用域的概念,使得let命令所声明的变量只在let命令所在的代码块有效,而且有暂时性死区的约束。
那么问题来了。
- 什么是暂时性死区?
- 什么是作用域?
var
变量提升
在了解var之前我们首先需要了解一下什么是变量提升。
下面是一道关于var变量提升的题目。
var a=99;
f();
console.log(a);
function f() {console.log(a);var a=10;console.log(a);
}
那么问题来了根据上面的打印输出得到的数据到底是什么呢,我相信很多人在没有了解这个机制之前都会说出是99,10,99之类的,但是实际的结果却是
undefined
10
99
为什么会这样的呢 因为当浏览器开辟出供代码执行的栈内存后,代码并没有自上而下立即执行,而是继续做了一些事情:把当前作用域中所有带var/function关键字的进行提前的声明和定义。所以实际上代码在运行到f()函数内部的时候,并没有先执行console.log,而是先执行了
var a;
//再执行
console.log(a);
//所以此时得到了undefined
接着往后走var a=10;
//此时相当于在定义var a之后给a赋值
var a;
a=10;
console.log(a);
在经过f()函数的局部变量以后,我们来到了全局变量,此时的console.log相当于执行了
var a=99;
console.log(a);
所以这就是变量提升,但是这种机制是非常的反人类的,我们都知道按部就班的执行代码是写出优秀代码的前提,这不仅给出了简洁明了的逻辑,也方便他人阅读,至此ES6,块级作用域的诞生了。
let
在ES6,JavaScript引入了let语法,不同于var声明方式的形式,let声明显得更加的严谨,在var语法中console.log(a); var a=10;
此时会得到undefined,而在let语法中console.log(a); var a=10
; 此时会得到Uncaught ReferenceError:Cannot access ‘a’ before initialization,即
未捕获的引用错误:在初始化之前无法访问“a”
暂时性死区
暂时性死区存在于块级作用域,在let、const声明变量之前该变量是不能被使用的。
let、const声明变量时,该变量被绑定在这个块级作用域,不再受外部影响,不被外部访问。
ES6 明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。
在ES6之前,使用typeof运算符永远都是安全的,如何理解呢?就是不管对哪个变量或对象进行类型判断,typeof都是不会报错的,但是在let引入后,typeof也不再安全
typeof x; =>此时会产生ReferenceError
let x;
所以什么是暂时性死区呢,即在let定义的变量之前的块级作用域都属于x的暂时性死区。
在ES6之前只有去全局作用域和局部作用域的概念,在ES6引入块级作用域的概念后即可通{}
来限制作用域。
{var x=10;
}
console.log(x);//输出10
{let x=10;
}
console.log(x);//ReferenceError:x not defined
具体的区别
声明后未赋值,表现相同
function(){var x;let y;console.log(x); //输出undefinedconsole.log(y);//输出undefined
}
使用未声明的变量,表现不同
console.log(x); //输出undefinedconsole.log(y);//报错ReferenceError:Cannot access ‘y’ before initializationvar x;let y;
重复声明同一个变量时,表现不同
function() {var x1='var first';let y1='let first';var x1='var second';let y1='let second';console.log(x1); //输出var secondconsole.log(y1);//直接报错 Cannot redeclare block-scoped variable 'x1'
}
变量作用范围,表现不同
function(){var x1='var first';let y1='let first';{var x1='var second';let y1='let second';}console.log(x1); //输出var secondconsole.log(y1);//输出let first,因为内部的let定义的x1是在块级作用域中是访问不到的
}
备注:使用 let 语句声明一个变量,该变量的范围限于声明它的块中。 可以在声明变量时为变量赋值,也可以稍后在脚本中给变量赋值。
使用 let 声明的变量,在声明前无法使用,否则将会导致错误。
如果未在 let 语句中初始化您的变量,则将自动为其分配 JavaScript 值 undefined