前端小白Earl笔记
闭包是JavaScript中的一个难点,也是面试中经常遇到的问题。
闭包的概念
我们先看看几个关于闭包的定义:
闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数。
——出自《JavaScript高级程序设计(第三版)》
函数对象可以通过作用域链相互关联起来,函数体内部的变量都可以保存在函数作用域内,这种特性在计算机科学文献中称为“闭包”。
——出自《JavaScript权威指南(第六版)》
闭包是指一个函数可以记住其外部变量并可以访问这些变量。在某些编程语言中,这是不可能的,或者应该以一种特殊的方式编写函数来实现。但在 JavaScript 中,所有函数都是天生闭包的。
——出自《现代JavaScript教程》
闭包就是能够读取其他函数内部变量的函数。例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。
——出自《百度百科》
闭包的基本格式和理解
闭包的理解
前文几个关于闭包的概念,虽然用词有很大不同,但是通过这些概念,我们大致可以对闭包有个初步的印象(如有错漏,请大神不吝赐教):在一个函数内部创建另一个函数,内层函数中访问到其外层函数的变量,就会形成闭包。不过如果说这些概念定义的闭包是广义的闭包,那我们日常提到的闭包,更像是狭义的闭包,通常是作为返回值,外部函数返回内部函数。由于闭包是内层函数引用了外层函数的变量,所以在调用完外层函数,外层函数中的变量也不会被垃圾回收,而内部函数在包含它们的外部函数之外被调用时,外层函数的变量就不会被释放。
闭包的基本格式
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语言精粹》
,