深入解析微信小程序中var、let、const的使用方法与区别

基本用法

  ES6 引入了 let 命令,用来声明变量。它的用法和 var 类似,但 let 声明的变量只在它所在的代码块内有效。

  举个例子,如果在代码块里分别用 letvar 声明两个变量,然后在代码块外调用它们,你会发现 let 声明的变量会报错,而 var 声明的变量却能正常返回值。这说明 let 声明的变量只在它所在的代码块内有效。

for 循环中的 let

for 循环的计数器非常适合用 let 来声明。比如,计数器 i 只在 for 循环体内有效,如果在循环体外引用它,就会报错。

  如果使用 var 声明计数器,最后输出的会是 10。这是因为 var 声明的变量在全局范围内都有效,每次循环都会改变 i 的值,导致所有循环内的函数都指向同一个 i,最终输出最后一轮的值。

  而如果用 let,变量仅在块级作用域内有效,最后输出的会是 6。这是因为每一轮循环的 i 都是一个新的变量,JavaScript 引擎会记住上一轮的值,并在本轮初始化时基于它进行计算。

块级作用域的父子关系

for 循环还有一个特别之处:设置循环变量的部分是父作用域,而循环体内部是一个单独的子作用域。这意味着函数内部的变量 i 和循环变量 i 不在同一个作用域,各自。

不存在变量提升

var 命令会发生“变量提升”现象,即变量可以在声明之前使用,值为 undefined。这种行为有些奇怪,因为按照常理,变量应该在声明后才能使用。

let 纠正了这个问题,它声明的变量必须在声明后使用,否则会报错。比如,用 var 声明的变量 foo 会发生变量提升,脚本运行时 foo 已经存在但没有值,所以输出 undefined。而用 let 声明的变量 bar 不会提升,声明前使用会报错。

暂时性死区

  只要块级作用域内存在 let 命令,它所声明的变量就“绑定”在这个区域,不受外部影响。比如,全局变量 tmp 和块级作用域内 let 声明的局部变量 tmp 冲突,导致在 let 声明前对 tmp 赋值会报错。

  ES6 明确规定,如果区块中存在 letconst 命令,这个区块对这些变量从一开始就形成了封闭作用域。在声明前使用这些变量会报错,这种现象称为“暂时性死区”(TDZ)。

typeof 不再安全

  “暂时性死区”还意味着 typeof 不再是一个百分之百安全的操作。比如,变量 xlet 声明,在声明前使用 typeof 会报错。而如果一个变量根本没有被声明,typeof 反而不会报错。

不允许重复声明

let 不允许在相同作用域内重复声明同一个变量。因此,不能在函数内部重新声明参数。

为什么需要块级作用域?

  ES5 只有全局作用域和函数作用域,没有块级作用域,这带来了一些不合理的情况。

  第一种情况是内层变量可能会覆盖外层变量。比如,if 代码块外使用外层变量 tmp,内部使用内层变量 tmp,但由于变量提升,内层变量会覆盖外层变量,导致输出 undefined

  第二种情况是循环变量泄露为全局变量。比如,变量 i 只用来控制循环,但循环结束后,它并没有消失,泄露成了全局变量。

ES6 的块级作用域

let 实际上为 JavaScript 新增了块级作用域。比如,函数有两个代码块,都声明了变量 n,运行后输出 5。这表示外层代码块不受内层代码块的影响。如果两次都用 var 定义变量 n,最后输出的值才是 10。

  ES6 允许块级作用域任意嵌套,外层作用域无法读取内层作用域的变量,但内层作用域可以定义外层作用域的同名变量。

块级作用域与函数声明

  ES5 规定函数只能在顶层作用域和函数作用域中声明,不能在块级作用域中声明。但浏览器为了兼容旧代码,仍然支持在块级作用域中声明函数。

  ES6 引入了块级作用域,明确允许在块级作用域中声明函数。块级作用域内声明的函数类似于 let,在块级作用域外不可引用。

do 表达式

  块级作用域本质上是一个语句,将多个操作封装在一起,没有返回值。现在有一个提案,使得块级作用域可以变为表达式,办法就是在块级作用域前加上 do,使它变为 do 表达式。

const 的基本用法

const 声明一个只读的常量,一旦声明,常量的值就不能改变。const 声明的变量不得改变值,这意味着声明时必须立即初始化,不能留到以后赋值。

const 的作用域与 let 相同,只在声明所在的块级作用域内有效。const 声明的常量也不提升,存在暂时性死区,只能在声明后使用。

const 的本质

const 实际上保证的是变量指向的内存地址不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在内存地址中,因此等同于常量。但对于复合类型的数据(对象和数组),const 只能保证指针固定,数据结构本身是可变的。

ES6 声明变量的 6 种方法

  ES5 只有两种声明变量的方法:varfunction。ES6 新增了 letconstimportclass,一共有 6 种声明变量的方法。

顶层对象

  ES5 中,顶层对象的属性与全局变量等价。ES6 规定,varfunction 声明的全局变量依旧是顶层对象的属性,而 letconstclass 声明的全局变量不属于顶层对象的属性。

© 版权声明
THE END
分享