主页

let和const

let和const

 

作用域

js中的作用域是由具体定义(声明)时的代码位置决定的。因为不管什么代码,一定是运行在某个作用域对象中的。

例如  for(let i=0; i<3; i++){ setTimeout(()=>{console.log(i);}); } 在输出i的值时,是在定义这个函数的位置处的作用域链中去查找值的,而不是其它地方。因为for每次执行时,圆括号都生成一个新的作用域对象,所以对应的输出的结果是 0 1 2。

更具体的分析是: 第一次进入for 循环时,生成 a0 = “圆括号0作用域对象”,再生成 b0 = “花括号0作用域对象”(圆括号的子作用域),在 b0 中定义了一个匿名的函数变量 b0.__匿名变量名0 = ()=>{console.log(i);},setTimeout的作用时将 a0.b0.__匿名变量名0 放入到系统队列中。 然后进入第二次for循环, let i=上次循环结束的值(即1), 生成 a1, b1 ...。 后面系统调用setTimeout队列时,首先执行  a0.b0.__匿名变量名0(),在执行这个函数时,会生成函数使用域对象c0(也就是{console.log(i);}对应的作用域对象),c0中会查找i的值,c0中没有定义i,所以到 bo中去找,也没找到,然后在a0中找,就找到了,值为0,所以输出0。然后执行 a1.b1.__匿名变量名1(),... , 同样的在a1中才找到 i 的定义,值为1,所以输出为1。

 

变量定义

参考 https://es6.ruanyifeng.com/#docs/let

js环境中,全局代码可以看作是位于一个主函数中(全局函数、入口函数,就像是 java中的main 一样)。

这样看来,var 定义的变量就只有一种作用域,就是函数作用域。一个函数对应一个作用域对象,每一个var定义的变量,都必然在某一个特定的作用域对对象中。

函数语句特指: function xxx(...){...} 这种, 函数表达式特指  (...)=>..., function (...){...} 这种。函数语句才可能会有变量提升,函数表达式只是一个值,而不是有名字的变量。

 

var的性质: 可重复定义,变量自动提升(定义自动提升到作用域开头,但赋值还留在原地),只能识别函数作用域,顶层var声明 <==> window.变量名=值, 两者等价。

 

function定义变量(不是函数表达式): es5的函数定义同 var (不使用严格模式的浏览器(支持es6的和不支持es6的)、不支持es6的非浏览器环境),es6的函数定义同 let(使用严格模式的浏览器、其它非浏览器环境(支持es6))。

 

let的性质:同一个作用域中不可重复定义(会报错)(不同作用域中可以重复声明,会产生变量覆盖的效果),没有自动提升(取而代之的是暂时性死区,从作用域开始到定义处这段区域引用变量会报错,typeof x 也会报错),可以识别函数作用域和块作用域。顶层let声明时同不会成为顶层属性。

const的性质,继承let: 额外加上 不允许修改变量的值。

import 声明的变量

class 声明的变量:性质同 let。

 

 

注意,变量的声明是以,或;结束的,一旦声明,后面就可以使用了。如 let i=3,d=i;   变量d声明时,i已经声明完成并赋值完成,所以可以成功取到值。 function aaa(i=3, d=i) 也是同样的道理,这个function此时站在变量定义的角度来说,完全可以看成是 let aaa(i=3, d=i)。 var x = x 不报错,因为引用x时,x已经声明是undefined(变量提升了), let x=x 报错,因为引用x时,x的声明还没完成。

注意,这里将js的所有作用域分成: 函数作用域(包括了全局作用域、普通函数体创建的作用域)、块级作用域(普通花括号的区域、for/while/if语句的花括号、for语句的圆括号)也就是除了函数作用域以外的所有花括号和圆括号生成的作用域。函数作用域和块级作用域是互斥的(虽然本质上来说,函数作用域也是广义的块级作用域的一种),这里是人为的划分成两种,所以这里的块级作用域说的是一种狭义的概念。

注意,函数定义的圆括号中的变量是函数体对应的作用域中的变量,也就是说圆括号不会形成一个单独的作用域。

注意,for、for in、for of 语句中的圆括号形成一个单独的块级作用域,是循环体的花括号对应作用域的父作用域。循环体作用域每次循环都会创建一个新的,且for、for in、for of 语句的圆括号每次循环也重新创建一个新的作用域,但 for 语句每次会将在圆括号中声明的变量赋值为上一次循环后的值,所以,如果在for的圆括号中使用const i=0,后面又i++就会报错。 所以for in 和 for of 圆括号中可以用const声明变量。 

例如  for(const i=0; i<3; i++){...} 之所以要报错,是因为 第一次进入for循环时,圆括号const i=0,然后执行循环体,再执行 i++,然后再 const i=上一轮结束后i的值,...,由于i是const定义的,所以i++报错。 for(const k in obj){...} 不报错,第一次进入for循环时,圆括号const k = 为obj的第一个key,然后执行循环体,然后 圆括号const k = 为obj的第二个key,然后执行循环体, ....

注意,浏览器中function定义,在严格模式下,是ES6,非严格模式下为 ES5。

注意,ES6 的块级作用域必须有大括号,如果没有大括号,JavaScript 引擎就认为不存在块级作用域。例如 if语句没有花括号时。

ES2020 在语言标准的层面,引入globalThis作为顶层对象。

 

var的缺点:函数中的 if体中var变量可能会覆盖函数外的同名变量,导致函数中引用该变量值为undefined。for循环圆括号中的var变量,会提升到整个函数作用域中。

let/const的优点:可以代替掉原来的 匿名IIFE 这种立即执行函数了。

 

posted @   平凡人就做平凡事  阅读(50)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示