在了解var,let,const的区别与作用时,首先得知道什么是作用域和变量提升
块级作用域:也叫局部作用域,js在es5之前,只有函数存在局部作用域,局部作用域下的变量,只会在当前作用域下进行访问和修改,在他之外是无法进行访问和修改的
function fn (){
var num = 100;
}
console.log(num);//ReferenceError 引用类错误,num没有定义
全局作用域:在整个script标签里都可以进行访问与修改
变量提升:js在代码执行前,系统会将所有的变量进行变量初始化(var 变量名;)
console.log(str); //undefined
var str = '我是js';
console.log(str); //我是js
造成第一次打印为undefined的原因就是因为此时的场景为
var str;
console.log(str); //undefined
var str = '我是js';
console.log(str); //我是js
而函数内部同样存在变量提升
var num = 10;
function fn (){
console.log(num); //nudefined
var num = 100;
}
fn();
而造成num为undefined的原因为:函数内部会再一次对变量进行初始化,而js的运行机制为,会优先考虑当前作用域下的变量,所以导致了num为undefined
var
用var声明的变量或函数,有变量提升,而且用var声明的变量没有块级作用域
let
let为es6新增,用let声明的变量,首先最大区别与var是,let拥有了块级作用域,其次,let没有变量提升另外,在for循环中,用let声明迭代变量,变量值会被值锁定
块级作用域体现:
if(true){
let num1=100;
var num1=200;
}
console.log(num1);//ReferenceError 引用类错误,num没有定义
console.log(num2);// 200
没有变量提升体现:
console.log(num1);//ReferenceError 引用类错误,num没有定义
let num1 = 100;
console.log(num1);//100
变量值锁定体现:
for(var i = 0;i<=4;i++){
setTimeout(() => {
console.log(i);
}, 0);
}
你会认为会打印的是0,1,2,3,4而实际打印的却是4,4,4,4,4,造成这一原因是因为,for循环是同步的,而定时器为异步函数,所以当定时器调用时,for循环已经跑完了,里面的i值已经为迭代变量i退出循环的值4了
在es6之前,常用解决这种问题的方法为
for(var i = 0;i<=4;i++){
(function(_index){
return setTimeout(() => {
console.log(_index);
}, 0);
})(i);
}
原理为在每一次循环进行时,自己调用一个函数并且把i作为参数传入,而函数是有块级作用域的,所以,每一次传入的i值将会被牢牢锁定在当前作用域下,以达到接下来说说明的let的变量值锁定效果
es6解决办法
for(let i = 0;i<=4;i++){
setTimeout(() => {
console.log(i); //0,1,2,3,4
}, 0);
}
暂时性死区:因为let与const没有变量提升所以在这之前访问都会报Uncaught ReferenceError/未捕获引用错误,在这一区域被称为'暂时性死区'
const
const与let的效果近似,区别在于用const声明的变量,变量的值无法改变
const str = "我是JavaScript";
console.log(str = 100); //TypeError 无法捕获类型错误 不能对常量进行修改
但是,通过const声明的数组,对象,以及函数里面的值,是可以进行修改的,所以,const一般用于声明这类类型所提供的
const myarr = [100,200];
myarr.push(300);
console.log(myarr);//[100, 200, 300]
const obj = {
num1:1,
num2:2
}
obj.num1 = 100;
console.log(obj.num1); //100