We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
说实话,闭包的文章都快烂了,但是依然打算自己写一下,加强自己的理解。
当函数可以记住并且访问所在的词法作用域。就产生了闭包。就算函数是在当前的词法作用域之外执行。 我觉得这个说法好记又好懂。
从闭包最开始的来源:《The mechanical evaluation of expressions》中,可以看到闭包有两部分组成:
对应到 js 就是:
上面提到的词法作用域,其实就是我们通常所说的作用域。JS所采用的作用域就是词法作用域。还有一种作用域叫做动态作用域,不过和我们没关系。
词法作用域就是写代码的时候,把变量和块作用域写在哪儿作用域就是哪儿。(还有欺骗词法作用域)所以要看代码写在哪儿,而不是在哪儿执行。
来看一下这个题,理解上面所说的意思:
let a = 0; function A () { let a = 1; add = function () { a += 1; } function B () { console.log(a); } return B; } let reserve = A(); reserve(); // ? add(); reserve(); // ?
let reserve = A();
reserve
function B
reserve();
B
a
function A
a = 1
add();
add
var、let、const
function
a += 1
a = 0
let a = 1
通过上面的例子,应该可以了解词法作用域了。就是函数无论在哪里被调用,也无论怎么调用,他的作用域都只由函数被声明时所处的位置决定。
说回闭包,刚才的代码其实已经产生了闭包了。就是return B。function B的作用域在function A里面,但是由于我们把function B给return出来了,在全局调用(在自己定义的词法作用域以外的地方执行)了function B,但是function B依然可以访问到他所在的作用域内部,通过作用域链的查找,打印出function A里的let a = 1。这里要区分和简单的作用域查找的区别。在它本身的作用域以外执行的,才是闭包。
return B
return
简单的说,function B依然有对该作用域的引用,这个引用就叫做闭包。
不只是在函数中返回一个函数可以形成闭包,像是setTimeout这种,也回形成闭包。因为setTimeout的回调函数是在全局执行的,但是他的作用域却是在定义时就确定了的。它依然保留着对内部的引用。
setTimeout
说到作用,最开始的模块模式,貌似就是用的闭包。有了闭包,就可以开辟一个独立的空间,来存储变量,好让变量不去污染全局,而且还可以在外面拿得到这些变量。
但是因为闭包的存在,就会影响到垃圾回收。本来,函数执行完成后,没有了对变量的引用,可以被回收掉了,但是因为闭包,所以还保留了引用,导致不能被垃圾回收。需要注意合理运用。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
说实话,闭包的文章都快烂了,但是依然打算自己写一下,加强自己的理解。
什么是闭包
当函数可以记住并且访问所在的词法作用域。就产生了闭包。就算函数是在当前的词法作用域之外执行。 我觉得这个说法好记又好懂。
闭包都是由哪些组成的呢
从闭包最开始的来源:《The mechanical evaluation of expressions》中,可以看到闭包有两部分组成:
对应到 js 就是:
词法作用域
上面提到的词法作用域,其实就是我们通常所说的作用域。JS所采用的作用域就是词法作用域。还有一种作用域叫做动态作用域,不过和我们没关系。
词法作用域就是写代码的时候,把变量和块作用域写在哪儿作用域就是哪儿。(还有欺骗词法作用域)所以要看代码写在哪儿,而不是在哪儿执行。
来看一下这个题,理解上面所说的意思:
let reserve = A();
的时候,reserve
就是function B
了reserve();
的时候,实际就是执行function B
,通过作用域链查找,B
里没有a
,function A
里有变量a = 1
,于是,打印1。add();
。注意看,add
声明的时候没有写var、let、const
,所以它是全局变量,而不是局部变量。那么function
里面的a += 1
会找到全局作用域下的a = 0
吗?实际上,并没有。根据词法作用域,我们可以知道,匿名函数里的a += 1
的作用域就在当前这个块里面,向上查找,找到的是function A
里面所声明的let a = 1
的这个a
。function B
所打印的a
是 1+1 得 2,而不是 0 + 1 得 1了 。通过上面的例子,应该可以了解词法作用域了。就是函数无论在哪里被调用,也无论怎么调用,他的作用域都只由函数被声明时所处的位置决定。
闭包
说回闭包,刚才的代码其实已经产生了闭包了。就是
return B
。function B
的作用域在function A
里面,但是由于我们把function B
给return
出来了,在全局调用(在自己定义的词法作用域以外的地方执行)了function B
,但是function B
依然可以访问到他所在的作用域内部,通过作用域链的查找,打印出function A
里的let a = 1
。这里要区分和简单的作用域查找的区别。在它本身的作用域以外执行的,才是闭包。简单的说,
function B
依然有对该作用域的引用,这个引用就叫做闭包。不只是在函数中返回一个函数可以形成闭包,像是
setTimeout
这种,也回形成闭包。因为setTimeout
的回调函数是在全局执行的,但是他的作用域却是在定义时就确定了的。它依然保留着对内部的引用。闭包的作用
说到作用,最开始的模块模式,貌似就是用的闭包。有了闭包,就可以开辟一个独立的空间,来存储变量,好让变量不去污染全局,而且还可以在外面拿得到这些变量。
但是因为闭包的存在,就会影响到垃圾回收。本来,函数执行完成后,没有了对变量的引用,可以被回收掉了,但是因为闭包,所以还保留了引用,导致不能被垃圾回收。需要注意合理运用。
参考
The text was updated successfully, but these errors were encountered: