JavaScript#JavaScript#作用域#闭包
JavaScript 入门第十天:作用域、变量提升与闭包
从变量可见性到作用域链,理解 let、var 的差异,并用闭包解释循环事件中的独立状态。
2 分钟阅读
第十天的主题是“一个变量在哪里可以被访问”。它解释了为什么 let 更适合循环,也为之前的点击次数练习补上了闭包这一层原因。
作用域决定变量可见性
全局作用域中的变量几乎到处可见,函数和代码块会创建更小的作用域。内部可以访问外部,外部不能反向访问内部:
const siteName = 'Myth'
function render() {
const title = '学习笔记'
console.log(siteName, title)
}
// console.log(title) // 错误
查找变量时,JavaScript 会从当前作用域开始,逐层向外找,这个查找关系叫作用域链。名称相同的内层变量会遮蔽外层变量,因此命名时应避免不必要的重复。
let、const 和 var 的关键差异
let 与 const 是块级作用域,var 是函数作用域,并且存在更容易误用的提升行为:
if (true) {
let scoped = '只在块内'
var leaked = '函数内可见'
}
console.log(leaked)
let 和 const 在声明前处于暂时性死区,访问会报错,这比得到一个意外的 undefined 更容易发现问题。日常代码默认使用 const,需要重新赋值时改用 let。
闭包保留函数创建时的环境
一个函数即使在外层函数执行完后,仍然访问得到外层变量,这种组合就是闭包:
function createCounter() {
let count = 0
return function () {
count += 1
return count
}
}
const nextCount = createCounter()
console.log(nextCount()) // 1
console.log(nextCount()) // 2
之前循环里为每个元素声明独立 count 的写法之所以可行,就是事件处理函数闭包住了那一轮的变量。闭包不是特殊语法,而是函数、作用域和引用自然组合出的结果。
学习这一章后,遇到“变量为什么是这个值”的问题,可以先问:它在哪个作用域声明?当前函数创建时能看到哪些变量?实际调用时又发生了什么?这比直接背题更可靠。