js中var,let,const的区别及相关面试题讲解
作者:遗憾随她而去.
一. var
1. var声明作用域
使用var在一个函数内部定义一个变量,就意味着该变量将在函数退出时被销毁:
function test(){ var a='hi' //局部变量 } test() console.log(a)//报错 //如果省略操作符 function test(){ a='hi' //全局变量 } test() console.log(a) //'hi' //去掉var操作符之后,就变成了全局变量,只要调用一次test(),就会定义这个变量,并且可以在函数外部访不 //推荐这样做,容易造成混乱
2. 声明提升 ,也就是把所有变量声明都拉倒函数作用域的订单,此外,使用var声明同一个变量也没有问题;
function test(){ console.log(a) var a='hi' } test() // undefined //等价于下列代码 function test(){ var a; console.log(a) a='hi' } //声明同一个变量 function foo(){ var a=10; var a=20; var a=30; console.log(a); } foo(); //30
二. let
1.let 跟var 的作用差不多,最明显的区别是,let声明的范围是块作用域,而var声明的范围是函数作用域
//var 没有块作用域 块作用域是是函数作用域的子集 因此let也没有函数作用域 if(true){ var name='matt'; let age=26; console.log(name); //matt console.log(age); //26 } console.log(name); //matt console.log(age); //age没有定义
2. let 也不允许同一个块作用域出现冗余声明
var name; var name; let age; let age; // age已经声明过了 //不在同一个块中可以重复声明 let age=30; console.log(age); //30 if(true){ let age=26; console.log(age); //26 } //在同一作用域内,不能混用 var 和 let 声明同名变量,否则会抛出 SyntaxError。 var name; let name;//SyntaxError let age; var age; //SyntaxError
3. let 有暂时性死区 就是let声明的变量不会在作用域中被提升
// var 会提升 console.log(name); //undefined var name='Matt' //let 不会提升. console.log(age)// age没有定义 let age=16; 在let声明之前的执行瞬间被称为"暂时性死区"
4. 使用let在全局作用域中声明的变量不会变成window对象的属性(var声明的则会)
var name='matt' console.log(window.name); //matt let age=26 console.log(window.age); //undefined
5.for循环中的let声明和var 声明
在let 出现之前,for循环定义的迭代变量会渗透到循环体外部;
for(var i=0;i<5;++i){ //循环逻辑 } console.log(i); //5 //改成使用let之后,这个问题就消失了,因为迭代变量的作用域仅限于for循环内部; for(let i=0;i<5;++i){ //循环 } console.log(i); //没有定义
还有个面试经常提及的问题,在for循环的循环体内定义一个定时器,循环结束后,查看结果
1. 使用var 的时候
for(var i=0;i<5;i++){ setTimeout(()=>console.log(i),1000) } //你可能会以为输出0,1,2,3,4 //实际会输出5,5,5,5,5
解释: 我们知道,循环结束的条件是i=5, 从事件循环机制的角度来分析上面的代码,是这样的:
调用堆栈:用于存储程序按顺序调用的函数的详细信息的堆栈。
1. 首先在Call Stack(调用堆栈)中执行同步代码var i=0,此时i小于5,执行下一行代码,发现是一个setTImeout计时器,它是一个宏任务,这个时候会被推入到WEB API中,计时器开始执行;
2. 执行i++,在Call Stack中进入下一次迭代循环,重复上面操作
其实上面的代码中WEB API一共存放过5个计时器,每个计时器进入到WEB API, 1s之后就会被推 入到QUEUE(队列)中(最后队列中也会有5个计时器),等待EVENT LOOP(事件循环)检测到Call Stack为空时,将QUEUE中每一个计时器推入到Call Stack执行,最后全部代码执行完成,从调用栈 中退出
使用var 的时候,由于每一次循环得到的迭代变量会被上一次的覆盖,最后i=5,退出循环,迭代变 量也被泄露了出去了,每一个计时器引用同一个i,因此会打印5个5
《JavaScript高级程序设计4》: 是因为在退出循环时,迭代变量保存的是导致循环退出的值 : 5
在之后执行超时逻辑时,所有i都是同一个变量,因而输出的都是同一个最终值
2.使用let 的时候
for(let j=0;j<5;j++){ setTimeout(()=>{ console.log('j',j) //1 2 3 4 5 }) }
个人理解 : for每次循环都是不同的块级作用域,let声明的变量是块级作用域的,所以也不存在重复声明的问题
《JavaScript高级程序设计4》: 在使用let声明迭代变量时,js引擎在后台会为每个迭代循环声明一个新的迭代变量,每个setTimeout引用的都是不同变量实例,所以console.log()输出的使我们期望的值,也就是循环执行过程中每个迭代变量的值
这种每次迭代声明一个独立变量实例的行为适用于所有风格的for循环,包括for-in和for-of循环
三. const
1. const 的行为与let基本相同,唯一一个虫重要的区别是用它声明变量时必须同时初始化变量,且尝试修改const声明的变量会导致运行时的错误
const age=26; age=36; //TypeError: 给常量赋值
2.const声明的限制只适用于它指向变量的引用,换句话说,如果const变量引用的是一个对象,那么修改这个对象内部的属性并不违反const的限制
const person={ } person.name='Matt'; //ok
3. js引擎会为for循环中的let声明分别创建独立的变量实例,虽然const变量跟let变量很相似,但是不能用const 来声明迭代变量(因为迭代变量会自增);
for (const i=0; i<10;++i)() //TypeError: 给常量赋值
总结
到此这篇关于js中var,let,const的区别及相关面试题讲解的文章就介绍到这了,更多相关js中var,let,const区别内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!