对js闭包的理解(JavaScript闭包closure)(1)

前端小白Earl笔记

闭包是JavaScript中的一个难点,也是面试中经常遇到的问题。

对js闭包的理解(JavaScript闭包closure)(2)

闭包的概念

我们先看看几个关于闭包的定义:

闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数。

——出自《JavaScript高级程序设计(第三版)》

函数对象可以通过作用域链相互关联起来,函数体内部的变量都可以保存在函数作用域内,这种特性在计算机科学文献中称为“闭包”。

——出自《JavaScript权威指南(第六版)》

闭包是指一个函数可以记住其外部变量并可以访问这些变量。在某些编程语言中,这是不可能的,或者应该以一种特殊的方式编写函数来实现。但在 JavaScript 中,所有函数都是天生闭包的。

——出自《现代JavaScript教程》

闭包就是能够读取其他函数内部变量的函数。例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。

——出自《百度百科》

对js闭包的理解(JavaScript闭包closure)(3)

闭包的基本格式和理解

闭包的理解

前文几个关于闭包的概念,虽然用词有很大不同,但是通过这些概念,我们大致可以对闭包有个初步的印象(如有错漏,请大神不吝赐教):在一个函数内部创建另一个函数,内层函数中访问到其外层函数的变量,就会形成闭包。不过如果说这些概念定义的闭包是广义的闭包,那我们日常提到的闭包,更像是狭义的闭包,通常是作为返回值,外部函数返回内部函数。由于闭包是内层函数引用了外层函数的变量,所以在调用完外层函数,外层函数中的变量也不会被垃圾回收,而内部函数在包含它们的外部函数之外被调用时,外层函数的变量就不会被释放。

闭包的基本格式

function f1(){ var n=999 function f2(){ alert(n) } return f2 } var fn = f1() fn() //999 //简约写法 function f1(){ var n=999 return function (){ alert(n) } } var fn = f1() fn() //999 //IIFE立即执行函数 !function (){ var n=999 fn = function (){ alert(n) } }() fn() //999

赋值的全局变量是独立的:

function f1(){ var n=1 var nAdd=function(){ alert(n ) } return nAdd } var fn1=f1() var fn2=f1() f1()() //1 f1()() //1 f1()() //1 fn1() //1 fn1() //2 fn1() //3 fn2() //1 fn2() //2 fn2() //3

同一个词法环境创建的不同嵌套函数,可以共享对同一个变量的访问:

function F1(){ var n=1 this.up=function(){ return n } this.down=function(){ return n-- } } var fn = new F1() alert(fn.up()) //1 alert(fn.up()) //2 alert(fn.down()) //1

闭包的作用

闭包可以用在许多地方,因为闭包允许将函数与其所操作的某些数据(环境)关联起来。闭包的最大用处有三个:

(1)外部可以读取函数内部的变量。

(2)封闭数据,实现数据私有,防止变量被污染。

(3)让这些变量的值始终保持在内存中。

function f1(){ var n=1 var nAdd=function(){ alert(n ) } return nAdd } var fn=f1() fn() //1 fn() //2 fn() //3 var n=9999 fn() //4 fn() //5 fn() //6

闭包可能引起的问题

由于闭包让变量的值始终保持在内存中,垃圾回收无法释放变量的内存,闭包有可能会导致内存泄漏。

闭包和作用域

理解闭包问题就重要的是要理解不同作用域之间的联系。下面这句话有助于理解闭包。

JavaScript中的函数运行在它们被定义的作用域里,而不是它们被执行的作用域里。

——出自《JavaScript语言精粹》

对js闭包的理解(JavaScript闭包closure)(4)

,