再探闭包
Willem Zhang Lv6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function apple () {
var count = 0

function output () {
console.log(count)
}

fruit(output)
}

function fruit (arg) {
arg()
}

apple() // 0

两个闭包:
1.apple()记住了自己的外部环境全局词法环境 所以fruit可以找到定义并执行
2.output()记住了自己的外部环境apple()函数的函数词法环境 所以count可以找到值 即使output在外部(全局)被调用

但是第一点也是作用域的体现,局部作用域找不到到全局去找,并且全局作用域还没有消失。
而第二点在执行output的时候由于将output作为值传给了arg,所以output在全局作用域执行,但是此时apple还是没有执行完,所以count一定没有被回收,但是假使apple执行完,由于output函数中有对外部词法环境的引用,外部词法环境也不会消失,因为每个函数在定义的时候都会引用自己的外部词法环境[[enviroment]],所以每个函数都有闭包。第二点强调的是函数在被定义的地方以外的地方引用,也能访问到count值,这是因为词法环境是静态的,与函数在哪里执行无关,只与代码的写法有关,在函数被定义的时候词法环境的关系就确定了。

函数记住并访问其所在的词法作用域,叫做闭包现象,而此时函数对作用域的引用叫做闭包。

1
2
3
4
5
6
7
8
9
function wait(message) {
// 这个回调函数的作用域是函数作用域,所以timer在wait中被定义,timer的外部环境是wait的词法环境,而不是setTimeout
// 但是此时由于timer在括号中,所以不能在wait中被调用。!!
setTimeout( function timer() {
console.log( message );
}, 1000 );
}

wait( "Hello, closure!" );

setTimeout是全局函数,所以timer在外部被调用,但是timer已经记住了自己定义的时候的词法环境wait,所以能够访问到wait的参数message,而且由于有对wait词法环境的引用,所以即使wait函数执行结束,message也没有被垃圾回收。
所以:同步时,由于记住自己外部词法环境,所以在任何地方被调用都能得到自己定义时所在词法环境的值;异步时,由于有对自己外部环境的引用,所以即使wait函数执行完毕,wait的词法环境也不会消失,1s后timer函数仍然能够访问到message参数。

只要使用回调函数(前提是函数所在词法环境与回调函数所在词法环境不同)就是在使用闭包,不管这个过程是同步还是异步的,因为回调函数被其他函数调用,回调函数在不同于自己被定义的地方被执行,但是此时由于回调函数有对自己定义时的词法环境的引用,所以可以得到自己所在词法环境的值。

ref

作用域闭包,你真的懂了吗?
感觉不是闭包的例子是错的,或者部分是错的
闭包的例子好像也是错的
但是例子给了启发

  • Post title:再探闭包
  • Post author:Willem Zhang
  • Create time:2021-11-27 18:46:29
  • Post link:https://ataraxia.top/2021/11/27/再探闭包/
  • Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.
 Comments