函数表达式是 JavaScript 中的一个既强大又容易令人困惑的特性。定义函数的方式有两种:一种是函数声明,另一种就是函数表达式。
函数表达式不同于函数声明。函数声明要求有名字,但函数表达式不需要。没有名字的函数表达式也叫做匿名函数。
1. 递归
递归函数是在一个函数通过名字调用自身的情况下构成的。
2. 闭包
闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数。
有关如何创建作用域以及作用域链有什么作用的细节,对彻底理解闭包至关重要。
在另一个函数内部定义的函数会将包含函数(即外部函数)的活动对象添加到它的作用域链中。
一般来讲,当函数执行完毕后,局部活动对象就会被销毁,内存中仅保存全局作用域。但是闭包的情况又有所不同。当函数返回了一个闭包时,这个函数的作用域将会一直在内存中保存到闭包不存在为止。
由于闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存。慎重使用闭包。
闭包与变量
作用域链的这种配置机制引出了一个值得注意的副作用,即闭包只能取得包含函数中任何变量的最后一个值。别忘了闭包所保存的是整个变量对象,而不是某个特殊的变量。
表面上看,似乎每个函数都应该返自己的索引值,但实际上,每个函数都返回10.
我们可以通过创建另一个匿名函数强制让闭包的行为符合预期
关于 this 对象
在闭包中使用 this 对象也可能会导致一些问题。我们知道,this 对象是在运行是基于函数的运行环境绑定的:在全局函数中,this 等于 window,而当函数被作为某个对象的方法调用时,this 等于那个对象。不过,匿名函数的执行环境具有全局性,因此其this 对象通常指向 window(当然,在通过 call() 和 apply() 改变函数执行环境的情况下,this 就会指向其他对象)。
每个函数在被调用时都会自动取得两个特殊变量:this 和 arguments。内部函数在搜索这两个变量时,只会搜索到其活动对象为止,因此永远不可能直接访问外部函数中的这两个变量。不过,把外部作用域中的 this 对象保存在一个闭包能够访问到的变量里,就可以让闭包访问该对象里。
3. 模仿块级作用域
JavaScript 没有块级作用域的概念。这意味着在块语句中定义的变量,实际上是在包含函数中而非语句中创建的。
用作块级作用域(通常称为私有作用域)的匿名函数的语法如下所示。
将函数声明包含在一对圆括号中,表示它实际上是一个函数表达式。而紧随其后的另一对圆括号会立即调用这个函数。
这种做法可以减少闭包占用的内存问题,因为没有指向匿名函数的引用。只要函数执行完毕,就可以立即销毁其作用域链了。
网友评论