JavaScript 定义闭包
■知识点
函数被调用时,会产生一个临时上下文活动对象,它是函数作用域的顶级对象,作用域内所有私有变量、参数、私有函数等都将作为上下文活动对象的属性而存在。
函数被调用后,在默认情况下上下文活动对象会被立即释放,避免占用系统资源。但是,当函数内的私有变量、参数、私有函数等被外界引用,则这个上下文活动对象暂时会继续存在,直到所有外界引用被注销。
但是,函数作用域是封闭的,外#无法访问。那么在什么情况下,外界可以访问到函数内的私有成员呢?
根据作用域链,内部函数可以访问外部函数的私有成员。如果内部函数引用了外部函数的私有成员,同时内部函数又被传给外界,或者对外界开放,那么闭包体就形成了。这个外部函数就是一个闭包体,它被调用后,它的调动对象暂时不被注销,其属性会继续存在,通过内部函数,可以持续读写外部函数的私有成员。
■实例设计
典型的闭包体是一个嵌套结构的函数。内部函数引用外部函数的私有成员,同时内部函数又被外界引用,当外部函数被调用后,就形成了闭包,这个函数也称为闭包函数。
下面是一个典型的闭包结构。
function f(x){ //外部函数
returnfunction(y){ //内部函数,通过返回内部函数,实现外部引用
return x + y; //访问外部函数的参数
};
}
var c = f (5); //调用外部函数,获取引用内部函数
console.log(c(6)); //调用内部函数,原外部函数的参数继续存在
解析过程简单描述如下。
第1步,在JavaScript脚本预编译期,声明的函数f和变量c,先被词法预解析。
第2步,在JavaScript执行期,调用函数f,并传入值5。
第3步,在解析函数f时,将创建执行环境(函数作用域),创建活动对象,把参数和私有变量、内部函数都映射为活动对象的属性。
第4步,参数x的值为5,映射到活动对象的x属性。
第5步,内部函数,通过作用域链,引用了参数x,但是还没有被执行。
第6步,外部函数被调用后,返回内部函数,导致内部函数被外界变量c引用。
第7步,JavaScript解析器检测到外部函数活动对象的属性被外界引用,无法注销该活动对象,于是在内存中继续维持该对象的存在。
第8步,当调用c,即调用内部函数时,可以看到外部函数的参数x存储的值继续存在,于是也就可以实现后续运算操作,返回x+y=5+6=ll。
■小结
下面的结构形式也可以形成闭包:通过全局变S引用内部函数,实现内部函数对外开放。
var c; //声明全局变量
function f(x){ //外部函数
c = function(y){ //内部函数,通过向全局变量开放实现外部引用
return x + y; //访问外部函数的参数
};
}
f (5); //调用外部函数
console.log(c(6)); //使用全局变量c调用内部函数,返回11
点击加载更多评论>>