在函数这一章节中,首先要有几个概念:
第一,定义函数的方式有两种方式:一种是函数声明,另一种是函数表达式。而函数声明会进行函数声明的提升;
第二,函数是一个对象,函数名实际上是一个指向函数对象的指针。
第三,arguments.callee 是一个指向正在执行的函数的指针。
闭包
闭包与变量
闭包只是有权访问另一个函数作用域中的变量的函数。一般来说,当函数执行完毕后,局部活动对象就会被销毁,内存中仅保存全局作用域(全局执行环境的变量对象)但是,闭包情况有所不同。
以上这个函数返回的是一个函数数组,注意该函数引用的是同一个变量i,每个函数都引用着保存变量i的同一个变量对象,所以在这个函数内部i的值都是10,与下图所写的函数进行对比思考,会较为容易理解与明白。
在以上这个函数中并没有直接把闭包赋值给数组,而是定义了一个匿名函数,并立即执行该匿名函数的结果赋值给数组。这里使用参数传值,因此将变量i的当前值复制给参数num。
关于this对象
this对象是在运行时基于函数的执行环境绑定的,在全局函数中,this等于window,而当函数被某个对象的方法调用时,this等于那个对象。
由于匿名函数的执行环境具有全局性,因此,其this对象通常指向window。当然,通过call()或apply()在改变函数执行环境的情况下,this就会指向其他对象。
内存泄漏
必须要记住:闭包会引用包含函数的整个活动对象,而其中包含着element,即使闭包不直接引用element,包含函数的活动对象中也仍然会保存一个引用,因此,有必要把element变量设置为null,这样就能够解除对DOM对象的引用,顺利地减少其引用数,确保正常回收其占用的内存。
模仿块级作用域(通常称为私有作用域)
在js中,变量 i 是定义在outputNumbers()的活动对象中,因此从它有定义开始,就可以在函数内部随处访问它,即使在后面错误的重新声明同一个变量,也不会改变它的值,遇到这种情况,js只会对后续的声明视而不见,但如果是对变量重新初始化便另当别论。
定义函数的方式是创建一个匿名函数,并把匿名函数负责给变量 。而调用函数的方式是在函数名称后添加一对圆括号。
前一个函数导致语法错误是因为js将function关键字当作一个函数声明的开始,而函数声明后面不能跟圆括号,然而,函数表达式后面可以跟圆括号,因此要将函数声明转换成函数表达式,即第二种写法。
在匿名函数中定义的任何变量,都会在执行结束后被销毁,而若匿名函数是一个闭包,它能够访问包含作用域中的所有变量。
私有变量
初始化未经声明的变量,总会创建一个全局变量。但在严格模式下给未经声明的变量赋值会导致错误。
小结
没有名字的函数表达式也叫做匿名函数;
递归函数应该始终使用arguments.callee来递归的调用自身,不要使用函数名,函数名可能发生变化;
当在函数内部定义了其他函数时,就创建了闭包;
当函数返回了一个闭包时,这个函数的作用域将会一直在内存中保存到闭包不存在为止;