二章
第11条:熟练掌握闭包
理解闭包的三个基本事实:
1. javaSricpt允许你引用在当前函数以外定义的变量。
2. 即使外部函数已经返回,当前函数仍然可以引用在外部函数所定义的变量。
3. 闭包可以更新外部变量的值。
1. javaSricpt允许你引用在当前函数以外定义的变量。
function makeSandwich(){ var magicIngredient = "peanut butter"; function make(filling){ return magicIngredient + "and" + filling; } return make("jelly"); } makeSandwich(); //"peanut butter and jelly"
请注意内部的make函数是如何引用定义在外部makeSandwich函数内的magicIngredient变量的。
2. 即使外部函数已经返回,当前函数仍然可以引用在外部函数所定义的变量。
function sandwichMaker(){ var magicIngredient = "peanut butter"; function make(filling){ return magicIngredient + "and" + filling; } return make; } var f = sandwichMaker(); f("jelly"); //"peanut butter and jelly" f("bananas"); //"peanut butter and bananas" f("marshmallows") //"peanut butter and marshmallows"
与 1 的不同之处:f的值为内部的make函数,调用f实际上是调用make函数。
即使sandwichMaker函数已经返回,make函数仍能记住magicIngredient的值。
这是如何工作的:JavaScript的函数值包含了比调用他们时执行所需要的代码还要多的信息。而且,JavaScript函数值还在内部存储他们可能会引用的定义在其封闭作用域的变量。那些在其所涵盖的作用域内跟踪变量的函数被称为闭包。
make函数就是一个闭包,其代码引用了两个外部变量:magicIngredient 和filling。每当make函数被调用时,其代码都能引用到这两个变量,因为该闭包存储了这两个变量。
函数可以引用在其作用域内的任何变量,包括参数和外部函数变量。
更加通用的sandwichMaker函数
function sandwichMaker(magicIngredient){ function make(filling){ return magicIngredient + "and" + filling; } return make; } var handAnd = sandwichMaker("ham"); handAnd("cheese"); //"ham and cheese" handAnd("mustard"); //"ham and mystard" var turkeyAnd = sandwichMaker("turkey"); turkeyAnd("Swiss"); //"turkey and Swiss" turkeyAnd("Provolone"); //"turkey and provolone"
函数表达式(更方便地构建闭包的字面量语法)
function sandwichMaker(magicIngredient){ function make(filling){ return magicIngredient + "and" + filling; } }
3. 闭包可以更新外部变量的值。
实际上,闭包存储的是外部变量的引用,而不是他们的值的副本。
因此对于任何具有访问这些外部变量的闭包,都可以进行更新。
一个简单的惯用法box对象的例子。(他存储了一个可读写的内部值)
function box(){ var val = unfefined; return { set:function(newVal){ val = newVal; }, get:function(){ return val; }, type:function(){ return val; } }; } var b = box(); b.type(); //"undefined" b.set(98.6); b.get(); //98.6 b.type(); //"number"
这个例子产生了一个包含三个闭包的对象。
这三个闭包是set、get、type属性。他们都共享访问val变量。set闭包更新val的值,随后调用get和type查看更新的结果。
提示:
- 函数可以引用定义在其外部作用域的变量。
- 闭包比创建他们的函数有更长的生命周期。
- 闭包在内部存储其外部变量的引用,并能读写这些变量。