var let const声明的区别
var 在ECMAScript的任何版本中都可以使用,而let和const只能在ECMASctipt6及更晚的版本中使用
var 关键字声明
- 使用var关键字可以声明任何类型的变量
var a ='abc';
a = 123;
这两条语句 第一条先是声明了一个变量a 里面存放了字符串类型的变量
第二条则改变这个变量的值,由字符串类型abc变成了数值类型123;
虽然不推荐改变变量的类型 ,但这种写法在ECMAScript中是完全有效的
- var 声明的作用域
在函数里使用var声明的变量在函数结束之后,变量会被销毁
在函数内部省略关键字var 可以创建一个全局变量(不推荐)
- var声明的提升
使用var关键字声明的变量会自动提升到函数作用域的顶部
所以 使用var反复声明一个变量都会在函数执行之前将var声明的变量提到函数顶部一个,所以不会报错。
let 关键字声明
- 使用let关键字也可以声明任何类型的变量
let a = 123;
function fn(){
let b = 345;
let c =function(){
console.log('hello!');
}
console.log(a);
}
- let 声明的作用域
let和var的作用差不多,但是有区别,最明显的区别就是:let声明的范围是块作用域
块作用域 是函数作用域的子集
而var声明的范围是函数作用域
var 声明 范围 函数作用域
function fn(){
if(true){
var name = 'hehe';
console.log(name); //hehe
}
console.log(name); //hehe
}
function fn(){
if(true){
let name = 'hehe';
console.log(name); // 输出hehe
}
console.log(name); //输出为空
}
- let 声明不允许出现冗余声明
同一个块作用域 不能出现重复声明
let a =123;
let a = "1222";// a has already been declared
在不同块之间可以声明同名变量
function fn(){
let a = "hehe";
if(true){
let a = 123;
console.log(a); //123
}
console.log(a); //hehe
}
声明冗余不会因混用var 和 let 而受影响 这两个关键字声明的并不是不同类型的变量
它们只是指出变量的相关作用域如何存在
let name = 123;
var name = "222"; // name has already been declared
var name = "222";
let name =123; // name has already been declared
- let 暂时性死区(let声明的变量不会在作用域中被提升)
在预编译过程中,js引擎也会注意到后面的let声明,但是不会在此之前以任何方式来引用未声明的变量,这就叫let的暂时性死区
function fn(){
console.log(a); //undefined 声明了 但是未定义
var a =123;
}
function fn(){
console.log(a); //错误,根本未声明
let a =123;
}
- let 在全局作用域中声明的变量,不会成为window对象的属性(var声明则会)
不过,let声明仍然在全局作用域中发生的,相应变量会在页面的声明周期内存续,因此,为了避免error,必须确保页面不会重复声明同一变量
var name =123 ;
console.log(window.name); //123
let age = "12222";
console.log(window.age); //undefined
- let不能使用条件式声明
使用var声明时,由于声明会被提升,js引擎会将多余的声明在作用域顶部合并为一个声明
因为Let的作用域是块,所以不可能检查前面是否已经使用let声明过同名变量
因为条件块中let声明仅限于该块,所以不能使用条件式声明
try{
console.log(age);
}
catch(error){
let age = 111;
console.log(age); //111
}
// let age 被限制在catch块中
// 所以这个赋值相当于全局赋值
age = 123; //123
- For循环中的let声明
在let出现之前,使用var声明 for循环定义的迭代变量会渗透到循环体外部;
js引擎会为for循环中let声明分别创建独立的变量实例。
for(var i = 0;i<5;i++){
}
console.log(i);
使用let之后,这个问题就解决了,因为迭代变量的作用域块仅限于for循环内部
for(var i = 0;i<5;i++){
}
console.log(i); //5,5,5,5,5
for (let i = 0;i<5;i++){
setTimeout(() => console.log(i),0) //0,1,2,3,4
}
const关键字声明
- const行为基本上与let相同,唯一重要的一点就是,const声明时必须要初始化变量,并且尝试修改const声明的变量的值时会导致运行错误
不允许重复声明
声明的作用域也是块
const name = 'hehe';
const name = 123; // name has already been declared
const name =123;
if(true){
const name = 'gaga';
}
console.log(name); // 123
- const声明的限制只适用于它所指向的变量的引用,换句话说,如果const变量引用的是一个对象,那么修改这个对象内部的属性并不违反const的限制
const abc = {
};
abc.name = "abcname"; //abc.name = "abcname"
声明风格
- 不使用var 使用let和const已经够了,而且变量有了明确的作用域,声明位置,以及不变的值
- const优先,let次之,使用const可以有效的判断那些变量的值永远不会变,同时可以迅速发现意外赋值导致的非预期错误