结果也是显示了money is not defined。所以当形成块级作用域时,外层是访问不了内层的。要是换成var money = 500;,这钱就会 “掉” 到外面,能被拿到 —— 这就是let的 “格子锁” 功能。
二、变量 “找不到?喊房东!”—— 作用域链
你在卧室里找行李,找不到咋办?喊 “房东”(外层作用域)啊!房东找不到,就喊 “大房东”(外外层作用域),一层一层往上喊,这串 “喊人的链条” 就是作用域链。
看个例子:
function myHome() {
var TV = "客厅的大电视";
let sofa = "客厅沙发";
{
let sofa = "卧室小沙发";
var eat = "客厅零食"; // var没格子锁,掉客厅里了
let clothes = "卧室睡衣";
console.log(TV); // 卧室里找不到,喊房东(客厅)→ 找到电视,输出“大电视”
console.log(sofa); // 卧室里有小沙发,直接拿→ 输出“小沙发”
}
console.log(sofa); // 客厅里的大沙发→ 输出“客厅沙发”
console.log(eat); // 零食掉客厅了→ 输出“客厅零食”
console.log(clothes); // 睡衣锁在卧室格子里→ 报错!拿不到
}
myHome();
这就离谱了:租客都走了,行李咋还在?
答案:因为保洁(内部函数)还 “惦记着” 这行李,物业(JS 引擎)就不会把卧室全清掉 —— 而是留个 “小储物箱”(这就是闭包),专门装保洁需要的行李(这里就是遗留行李)。
大白话翻译闭包:
租客退租了,但保洁把他的行李扣在储物箱里,走到哪带到哪 —— 这储物箱就是闭包。
还没懂的话我再举个例子:
假设你有一个不听话的儿子,他跟你断绝关系出去闯荡,幸运的是他出去之后你们的老房子就拆迁了,于是你拿着拆迁补贴买了一套新房子,但你于心不忍,你怕儿子走投无路回来找你,但是房子又拆迁了,这时候你就会在这个拆迁遗址立一个牌子或者什么做标记,让你儿子知道你搬到哪里了,而这个牌子就是闭包。虽然老房子没了,但是这个牌子有它的作用----提醒你儿子新家的地址,你儿子如果回来会用得到这个作用。
虽然已经出栈,但依旧保留函数要用到的方法,这就是闭包的核心。
再看一个例子:为啥能输出 1-5?就是因为闭包把 “每个房间的行李” 都扣下来了:
var arr = [];
for (var i = 1; i <= 5; i++) {
function foo(j) {
arr.push(function(){
console.log(j);
})
}
foo(i);
}
for (let n = 0; n < arr.length; n++) {
arr[n]();
}