目录
前言
var、let、const都是javascript声明变量的关键字,在ES6之前的版本中,用于声明变量的关键字只有var,并且没有块级作用域,只有函数作用域和全局作用域,但在ES6中已改变这种状况。ES6引入了let和const两个关键字,它们既可以用于声明变量,还能够将变量绑定到当前所处的任意作用域中,换句话说,就是把变量的作用域封闭在所处的代码块(即花括号字符“{”和“}”之间的区域,例如if条件语句中的代码)中,如此一来就形成了块级作用域。引入块级作用域解决了这两个问题:1.内层变量可能覆盖外层变量,2.用来计数的循环变量泄露为全局变量两个问题。下文会说明let和const两个关键字与var之间的不同。
一、作用域
var声明变量的作用域
var声明的变量不存在块级作用域,属于全局作用域。但是存在函数作用域,在函数中用var声明的变量在函数外不能使用,也不能跨函数使用(在其他函数里使用)。
if(true){
var num=1
}
console.log(num);//输出结果是1,说明变量是全局的
function add(num){
var num1=2
return num+num1
}
console.log(add(num));//输出结果3,说明变量是全局的
console.log(num1);//输出ReferenceError: num1 is not defined,存在函数作用域
let声明变量的作用域
let声明的变量存在块级作用域,由{ }包裹,不能跨块访问。也存在存在函数作用域,在函数中用let声明的变量在函数外不能使用,也不能跨函数使用(在其他函数里使用)。
if(true){
let num=1
}
console.log(num);//输出ReferenceError: num is not defined,存在块级作用域
function add(num){
let num1=2
return num+num1
}
console.log(add(num));//输出结果3,说明变量是全局的
console.log(num1);//输出ReferenceError: num1 is not defined,存在函数作用域
const声明变量的作用域
const声明的变量存在块级作用域,由{ }包裹,不能跨块访问。也存在存在函数作用域,在函数中用const声明的变量在函数外不能使用,也不能跨函数使用(在其他函数里使用)。
if(true){
const num=1
}
console.log(num);//ReferenceError: num is not defined,存在块级作用域
function add(num){
const num1=2
return num+num1
}
console.log(add(num));//输出结果3,说明变量是全局的
console.log(num1);//输出ReferenceError: num1 is not defined,存在函数作用域
内层变量可能覆盖外层变量\n用来计数的循环变量泄露为全局变量
二、变量提升
var声明的变量和函数存在变量提升
变量提升又称声明提前:JavaScript 引擎会在执行代码之前先进行一次预编译(预解析),把所有的 var 变量声明和函数声明提升到当前作用域的顶部。如下代码所示:
console.log(num) // 输出undefined而不是ReferenceError: num is not defined说明num已被定义但未赋值
var num = 1
function Test() {
console.log(num1) // 输出undefined而不是ReferenceError: num1 is not defined
var num1 = 2
console.log(num1);//输出2
}
Test()
console.log(num) // 输出1
经过预解析实际后代码如下:
var num
function Test() {
var num1
console.log(num1) // 输出undefined而不是ReferenceError: num1 is not defined
num1 = 2
console.log(num1);//输出2
}
console.log(num)
num=1
Test()
console.log(num)
let和const声明的变量和函数不存在变量提升
let声明
console.log(num) // 输出uReferenceError: Cannot access 'num' before initialization
let num = 1
const声明
console.log(num) // 输出uReferenceError: Cannot access 'num' before initialization
const num = 1
三、暂时性死区
暂时性死区是指在代码块内,使用let或const命令声明变量之前的区域,该变量在此区域内是不可用的,即属于该变量的“死区”。
因为let,const不存在变量提升所以导致死区的形成,但是var不存在暂时性死区的情况。
在ES6中,暂时性死区的概念是为了防止在变量声明前就使用这个变量,从而导致意料之外的行为。具体来说,当在代码块内尝试访问一个使用let或const声明的变量,但在该声明之前就已经引用了这个变量时,会触发一个ReferenceError错误。可以看如下代码方便理解:
let a = 1
{
//死区开始
console.log(a) //死区:因为存在块级作用域无法访问外部的a,也无法访问到内部的a
//死区结束
let a = 2 //此区域块内创建了a并绑定了值
console.log(a)//此时获取到内部的a
}
四、重复声明
let和const在同一作用域内,相同的变量不可以重复声明
let同一作用域下:
let num=1
let num=2 //报错SyntaxError: Identifier 'num' has already been declared
const同一作用域下:
const num=1
const num=2 //报错SyntaxError: Identifier 'num' has already been declared
let、const同一作用域下 :
let num=2
const num=1 //报错SyntaxError: Identifier 'num' has already been declared
不同作用域下:
let num=1
if(true){
let num=1//不报错
}
var在同一作用域内,相同的变量可以重复声明变量
var num=1
var num=2//不报错
五、全局属性
var关键字声明的变量会挂载到window全局属性上,但是let和const声明的则不会。
const name='张三'
console.log(window.name);//无
let age=13
console.log(window.age);//undefined
var hobby='唱歌'
console.log(window.hobby);//唱歌
六、初始值
1、使用const定义变量时必须赋予其初始值,而var和let则不用
const a//'const' declarations must be initialized
a=1//这种方式是不正确的
const a=1//必须对其赋值
2、const声明的常量必须进行初始化,不允许对常量重新赋值
const a=1
a=2//错误,不能重新赋值 TypeError: Assignment to constant variable.
3、如果const定义的是一个复杂数据类型,可以添加、删除、修改值,但不能改变原有类型
const arr=[1,2,3]
arr[0]=4//可以修改值
arr={
name:'张三',
age:13
}//错误,不可以修改原有类型
七、for循环中的循环变量
用var定义的迭代变量会渗透到for循环的外部,但用let定义变量可以解决这个问题。
for (var i = 0; i < 5; ++i) {
}
console.log(i); // 5,var定义的for循环的迭代变量渗透到外部
解决办法改用let,变量i只存在于当前作用域:
for (let i = 0; i < 5; ++i) {
}
console.log(i); // ReferenceError: i 没有定义,let定义的循环变量不会渗透到外部
使用setTimeout定时器迭代用var定义循环变量可能会出现以下问题:
for (var i = 0; i < 5; ++i) {
setTimeout(() => console.log(i), 0)
}
// 你可能以为会输出 0、1、2、3、4
// 实际上会输出 5、5、5、5、5
之所以会这样,是因为在退出循环时,迭代变量保存的是导致循环退出的值:5。同步执行完执行异步代码:在执行setTimeout时,所有的 i 都是同一个变量,因而输出的都是同一个最终值。
for (let i = 0; i < 5; ++i) {
setTimeout(() => console.log(i), 0)
}
// 会输出 0、1、2、3、4
而在使用 let 声明迭代变量时,JavaScript 引擎在后台会为每个迭代循环声明一个新的迭代变量。每个 setTimeout 引用的都是不同的变量实例,所以输出的是我们期望的值,也就是循环执行过程中每个迭代变量的值。
参考文献:【var、let、const的区别 - CSDN App】http://t.csdnimg.cn/w432v