JavaScript 学院 #2:闭包
欢迎来到这个新学院!在这里,我不会从头开始讲解 JavaScript,而是会讲解一些 JavaScript 概念,帮助你理解 JavaScript 引擎!
今天我就来教大家什么是Closure
?
简短定义
AClosure
是一个可以访问其自身范围之外的变量的函数。
🤔...
好吧,我们来举个例子!
let b = 5
function toto(a) { return a + b }
toto(1) // 6
当 JS 引擎将传递给函数时,它将检查每个变量是否在当前上下文中可用,这里只有变量a
可用,因为它是参数。
但是当检查b
变量时,它会检查该变量在函数上下文中是否可用!所以它会检查该变量在外部上下文中是否可用!
这才叫一个Closure
!
但是 JS 引擎需要采取一些技巧才能在函数中保留外部变量访问!
实际上,JS 引擎会将外部变量(b
)存储在内存中heap
!因此,它会保留对该变量的引用,当我们调用该函数时,该变量将可用!
事实上这outer variable
是存储在一个对象名称中Lexical environment
。
什么是Lexical environment
?
词法环境只是“理论上”存在!它赋予函数调用所需的一切!它由两部分组成:
-
存储局部变量的环境记录。
-
引用此函数中使用的外部变量。
现在让我们看看 JS 引擎如何在函数中管理变量作用域
const toto = 5 // declared in the global scope
function hello () = {
let a = 35
let toto = 45
console.log(a + toto)
}
hello() // 80
为什么在上面的例子中,当我们调用console.log(a + toto)
toto 时,它的值是45
而不是5
?
当我们调用一个函数时,JS 引擎会检查变量是否存在于当前上下文(环境记录)中,如果是,则取该值,否则,它会检查变量是否存在于外部上下文中,直到到达Global Scope
。
另一个例子来理解这种行为!
const toto = 'toto global | ' // declared in the global scope
const b = 'b global | '
function hello () {
const a = 'a hello | '
const toto = 'toto hello | '
const c = 'c hello | '
return function hey () {
const c = 'c hey | '
console.log(a + toto + b + c)
}
}
hello()() // a hello | toto hello | b global | c hey |
你看懂其中的逻辑了吗?
目的Closure
它使用更多的资源,那么为什么要使用闭包?
此外,我们还可以创造副作用!
let toto = 55
function change() {
toto = 69
}
change()
console.log(toto) // 69
但是您可以封装数据并创建一些秘密和受保护的变量!
function hello() {
let counter = 0
return function () {
counter++
console.log(counter)
}
}
const upCounter = hello()
upCounter() // 1
upCounter() // 2
upCounter() // 3
您的变量是安全的,您只能通过函数返回来更改它hello
!
此外,每个实例hello()
都有其自己的上下文!
const upCounter1 = hello()
const upCounter2 = hello()
upCounter1() // 1
upCounter1() // 2
upCounter2() // 1
关于闭包的测验
const arrFuncs = []
for(var i = 0; i < 5; i++) {
let toto = function () {
return i
}
arrFuncs.push(toto)
}
console.log(i) // i is 5
arrFuncs.forEach(arrFunc => console.log(arrFunc())) // All logs
为什么它记录了5
而不是记录了0, 1, 2, 3, 4
?!
让我们一步一步地理解这一点!
for(var i = 0; i < 5; i++)
等于
var i
for(i = 0; i < 5; i++)
由于我们使用了 var,因此变量i
被提升到global scope
!
所以当我们做
let toto = function () {
return i
}
我们正在使用 toto 函数作为Closure
!
我们知道,闭包用于reference
外部变量(var i 是一个外部变量,因为它在全局范围内声明)
因此,当我们执行每个闭包时(在期间forEach
),我们将从中获取变量值reference
,此时的当前值是5
!
所以这就是我们console log 5
五次的原因!
我希望你喜欢这篇文章!
🎁 如果您在Twitter上关注我并给我发送消息,您可以Underrated skills in javascript, make the difference
免费获得我的新书😁 并节省 19 美元💵💵
或者在这里获取
🇫🇷🥖 对于法国开发者,你可以查看我的YoutubeChannel
☕️ 你可以支持我的作品🙏
🏃♂️ 你可以关注我 👇
🕊 推特:https://twitter.com/code__oz
👨💻 Github:https://github.com/Code-Oz
你也可以标记🔖这篇文章!
文章来源:https://dev.to/codeoz/javascript-academy-2-closures-2j78