1.var是ES5提出的,let和const是ES6提出的。
2.const声明的是常量,必须赋值
(1)一旦声明必须赋值,不能使用null占位。
(2)声明后不能再修改
(3)如果声明的是复合类型数据,可以修改其属性3.let和var声明的是变量,声明之后可以更改,声明时可以不赋值
4.var允许重复声明变量,后一个变量会覆盖前一个变量。let和const在同一作用域不允许重复声明变量,会报错。
5.var声明的变量存在变量提升(将变量提升到当前作用域的顶部)。即变量可以在声明之前调用,值为undefined。
6.let和const不存在变量提升。即它们所声明的变量一定要在声明后使用,否则报ReferenceError错。
7.var不存在块级作用域,var是函数作用域。let和const存在块级作用域。
8.ES5中作用域有:全局作用域、函数作用域。没有块作用域的概念。
ES6(简称ES6)中新增了块级作用域。块作用域由 { } 包括,if语句和for语句里面的{ }也属于块作用域。(注:块级作用域:即在 {}花括号内的域,由 { }包括,比如if {}块、for () {}块。 函数作用域:变量在声明它们的函数体以及这个函数体嵌套的任意函数体都是有定义的。)
详解
var关键字:
定义变量可以使用var,后面跟变量名,如var a = 1;这样就是将1赋值给a;当然a可以保存任何类型的值。我们还可以改变a保存的值,也可以改变值的类型,如var a=1;==> a ='hello';
var的作用域
在使用var定义一个变量的时候,它会成为包含它的函数的局部变量,
如:
function txt(){ var a = 1;//局部变量 } txt(); console.log(a)//会报错
若想将var定义的变量成为全局变量,则可以这样:
function txt(){ a =1;//全局变量 } txt(); console.log(a)//1
在去掉var关键字之和,a就成为了全局变量,只要调用了txt()这个函数,就会定义这个变量,并且会在外部访问到。
(注:虽然可以通过省略var来实现定义全局变量,但不推荐这么做,因为这在维护起来会很难维护,容易看代码的时候看迷。而且在严格模式下,这样省略就会造成给为声明的变量赋值,就会报错。)
var声明提升function foo() { console.log(age); var age = 26; } foo(); // undefined
这样写是不会报错的,因为在使用这个关键字声明的变量会自动提升到函数作用域的顶部,也就是这样:
function foo() { var age; console.log(age); age = 18; } foo(); // undefined
这个变量提升也就可以实现多次使用var声明同一个变量也没啥问题,通常可以说最后声明的变量将前面的变量覆盖掉了,如:
function foo() { var age = 16; var age = 9; var age = 18; console.log(age); } foo(); // 18
let关键字
let和var的作用是差不多的,都是用来声明变量的,最大的区别就是,let声明的范围是块级作用域,而var是函数作用域。
(注:块级作用域:即在 {}花括号内的域,由 { }包括,比如if {}块、for () {}块。 函数作用域:变量在声明它们的函数体以及这个函数体嵌套的任意函数体都是有定义的。)
如:
if (true) { var name = '伍叁'; console.log(name); // 伍叁 } console.log(name); // 伍叁
if (true) { let age = 21; console.log(age); // 21 } console.log(age); // Error: age 没有定义
这里的age在if块外了,所以不能被引用。
var可以声明一个变量多次,而let就不行了,let是不允许在同一个块级作用域中出现冗余声明的哈。如:
var name; var name; let age; let age; // Error;标识符 age 已经声明过了
但是JavaScript引擎会记录用于变量声明的标识符及其所在的块级作用域,所以嵌套使用相同的标识符不会报错,这是因为在块级作用域中没有重复声明。如:
var name ='伍叁'; consloe.log(name); //伍叁 if(true){ var name='嗨嗐'; console.log(name);//嗨嗐 } //----------- let age =18; consloe.log(age)//18 if(true){ let age = 21; consloe.log(age)//21 }
对申明冗余报错不会因为混用let和var而受影响,这两个声明的并不是不同的变量,它们只是指出变量在作用域中是如何存在的。如:
let name = "111" var name = 'aaa' console.log(name)
暂时性死区
上面说了var会有变量提升,而let却没有。如:
// name 会被提升 console.log(name); // undefined var name = '伍叁'; //------------------ // age 不会被提升 console.log(age); // ReferenceError:age 没有定义 let age = 18;
这就说明了,在log的时候,age还没有声明,这就会出现暂时性死区。
全局变量
在使用var这个关键字的时候,它会成为window对象的属性,而let则不会。如:
var name = '伍叁'; console.log(window.name); // '伍叁' //------------ let age = 18; console.log(window.age); // undefined
虽然let也是在全局声明的,但是为了避免出现error,所以要确保整个页面不能重复声明同一个变量。(注:要知道函数作用域和块级作用域的区别)
for循环中的let
在let没有出现之前,for循环定义的迭代变量会渗透出去,也就是渗透到循环体外部。如:
for (var i = 0; i < 5; ++i) { // 循环逻辑 } console.log(i); // 5
在let出现之后这个问题就没了,因为let有块级作用域,如:
for (let i = 0; i < 5; ++i) { console.log(i)// 会输出 0、1、2、3、4 } console.log(i); // ReferenceError: i 没有定义
const声明
const与let基本相同,区别是const是用来定义常量的,尝试修改const声明的变量会导致运行上报错。const也不可以重复声明,const也是块级作用域。如:
//赋值 const name = '伍叁' name='阿巴阿巴'//error //重复声明 // const 也不允许重复声明 const name = 'tt'; const name = 'Nice'; // Error //块级作用域 const name = '伍叁'; if (true) { const name = '嘿哈'; } console.log(name); // 伍叁
const变量如果引用的是一个对象,修改这个对象内部的属性则不会报错。
const data = {}; data.name = '伍叁'; // 没问题的啦老铁
但const不能像let一样用来声明迭代的变量,如for循环,因为迭代的变量会自增。当然这样对于for...in和for...of这种循环意义就不一样了。如:
for (const key in {a: 1, b: 2}) { console.log(key); } // a, b for (const value of [1,2,3,4,5,6,7,8]) { console.log(value); } // 1, 2, 3, 4, 5, 6, 7, 8
小结:
1.不使用var
出现了let和const之后,会发现在定义变量的时候有了明确的作用域、声明位置(当初刚学JavaScript的时候为了搞明白变量提升熬了好久)和不变的值。2.const优先,let次之
(这个是作者说的跟我伍叁没啥关系,因为我喜欢用let,我暂时没有那么好业务逻辑)按作者的意思就是使用const声明可以让浏览器知道这个变量是不会被改变,会让代码分析工具知道有哪些不合法的赋值操作(就是减少骚操作)。所以很多开发者认为优先使用const,在要修改的时候,再改为let。
这里是:
原文链接:https://blog.csdn.net/weixin_61994154/article/details/123515475