let const var 的区别
var let const 的特性和区别
var:存在变量提升;不存在块级作用域(全局变量);可重复声明变量.可重新赋值;
let:不存在变量提升,存在块级作用域(局部变量);不可重复声明,可重新赋值。
const:不存在变量提升;存在块级作用域(是局部变量,只能在代码块中起作用。不可重复声明,不可重新赋值。
let的基本用法
1.作用域
使用var操作符定义的变量会成为包含它函数的局部变量,例如使用var在一个函数的内部定义一个变量,就意味着该变量在函数退出时被销毁。
1 function test() { 2 var message = "hi";//局部 3 } 4 test(); 5 console.log(message);//error
var声明的范围是函数作用域,而let声明的范围时块作用域。
if (true) { var message = "hi"; console.log(message);//hi } console.log(message);//hi if (true) { let message = "hi"; console.log(message);//hi } console.log(message);//error
message变量之所以不能在if块外部被引用,是因为他的作用域仅限于该块内部。块作用域是函数作用域的子集。因此适用于var的作用域限制,同样适合于let。
2.块级作用域变量
1 a = 0;//全局变量 2 console.log(window.a)//0 3 let b = 1;//块级作用域变量。 4 console.log(window.b)//undifidend
3.for循环
var a = []; for (var i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6]();//10
上面函数中,变量i是var命令声明的,在全局范围内都有效,所以全局只有一个变量i,每一次循环,变量i的值都会发生改变,而循环内被赋给数组a的函数内部的console。log(i),里面的i指向的就是全局的i。也就是说,所有数组a的成员里面的i,指向的都是同一个i,导致运行时输出的是最后一轮的i的值,所以输出就是10。
如果使用let,声明的变量仅在块级作用域内有效,最后输出的就是6。
var a = []; for (let i = 0; i < 10; i++) { a[i] = function() { console.log(i); }; } a[6]();//6
上面代码中,变量i是let声明的,当前的i只是在本轮循环中有效,所以每一次循环都创建一个块级作用域,所以最后输出的是6。
另外,for循环还有一个特别之处,就是设置循环变量的那部分是一个父级作用域,而循环体内部是一个单独的子作用域。
1 for (let i = 0; i<3; i++) { 2 let i = 'abc'; 3 console.log(i); 4 }//abc*3
上面代码正常运行,输出三次abc。这表明函数内部的变量i与循环体i不在同一个作用域。
2.不允许重复声明
let 不允许在相同的作用域下,重复声明同一个变量。
function() { let a = 0; var a= 0; }//报错 function () { let a = 0; let a = 2; }//报错
因此,不能再函数内部重复声明变量。
function func (arg) { let arg;//报错 } function func (arg) { { let arg;//不报错 } }
3.不存在变量提升
var 命令会发生变量提升现象,即变量可以在声明之前使用,值为undefidend。这种现象多多少少是有点奇怪的,按照一般的逻辑,变量应该在声明语句之后才可以使用。
为了纠正这种现象,let 命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错。
//var console.log(foo);//输出undefidend var foo = 2; //let console.log(a);//ReferenceError let a = 1;
4.暂时性死区
从let块级作用域开始,到初始化位置,称作暂时性死区,对于变量的暂存死去中使用的变量会报错ReferenceError。
1 var tmp = 1; 2 if (true) { 3 tmp = 2; 4 let tmp;//ReferenceError 5 }
上面代码中,存在全局变量tmp,但是块级作用域内let又声明了一个局部变量tmp,导致后者绑定这个块级作用域,所以在let声明变量前,对tmp赋值会报错。
ES6规定,如果区块中存在let和const命令,这个取快对这些命令声明的变量,从一开始就形成了封闭作用域,凡是在声明之前就是用发这些变量,就会报错。
const
const是constant(常量)的缩写,const和let一样也是用来声明变量的,但是const是专门用于声明一个只读常量的,顾名思义,常量的值是不可改变的。const一旦声明,常量的值就不可改变。
1 const Name = '张三‘; 2 Name = '李四’;//报错,常量不能修改
与let一样,只在块级作用域起作用。
if(1) { const Name = 'zs'; } alert(Name);//报错
与let一样,不存在变量提升,必须先声明后使用。
if(1) { alert(Name);//报错 const Name = ‘贤主’; }
与let一样,不可重复声明一个相同的变量。
var Name = '贤主‘; const Name = '蜘蛛侠’;//报错
声明后必须赋值
const Name;//报错
常量是一个对象 传址赋值
1 const person = {“name”: “贤主”}; 2 person.name = "老师"; 3 person.age = "18"; 4 console.log(person);//{name:老师,age:18}
怎么常量person好像被修改了,name改变了,还添加了age,怎么没有报错?还正常输出,不是说常量不可改变的吗?
这个时候我们先引入一个概念,在赋值的过程中,我们可以分为传值赋值和传址赋值,这里我们用到了传址赋值,什么叫传址赋值?
传址:在赋值过程中,变量实际上存储的是数据的地址(对数据的引用),而不是原始数据或者数据的拷贝。
用const来声明一个对象类型的常量,就是传址赋值,而不可修改的是对象的内存中的地址,而不是对象本身,所以这就解释了干菜这段代码为什么不会报错,而是正常输出了。
因为修改的不是person本身,修改的是name属性和增加一个属性age,而地址没有变,也不可变。没有违背常量不可改变的约定。但是如果:
const person = {"name":"张三”};
person.age = 20;
console.log(person);//{name:张三,age:20}
person = {};//报错 给常量person赋值
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具